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

[System] Bonus Mod & SetUnitMaxState

Level 11
Joined
Feb 18, 2004
Messages
394
Note: Consider this a public beta. I'm too lazy to do extensive testing.

Summary

Bonus Mod is a system for easily applying a reversible bonus to a specific unit. With a single function call, you can increase a single units damage / armor / sight range / etc. by any chosen amount. Bonuses like damage, armor, intelligence and agility will show up next to the units base stat, in green or red depending on if the bonus is negative or positive.

SetUnitMaxState is a function originally written by Blade.dk which abuses a bug introduced in some patch. It allows you to easily change the maximum life / mana of a single unit. It works by the fact that life / mana bonus abilities with more than one level will only ever add the bonus for level 1. However, when you remove the ability, it will remove the amount of life it is set up to add for that level. By removing a negative life bonus, a unit would gain life.

Implementation Instructions

These two systems can be added to a map independently of each other. (They are presented together due to their complimentary natures)

To add one of these systems to your map, simply copy and paste each library in to its own empty custom-script trigger. You will also need to create a large number of abilities for Bonus Mod, and two for SetUnitMaxState. However, you can use the following Object Merger macros to do the hard work for you. Simply copy them in to empty triggers, save your map, close it and re-open it in the editor, and disable the triggers you copied them in to. All the abilities these systems use will then be present in your map:

JASS:
// About these macros:
//
// The first paramiter is the rawcode for the ability. The convention used here by default is:
// Zx followed by an uppercase letter, unique to the bonus, followed by a 0-9-a-z representing
// the base of two the ability applys.
//
// The second paramiter is the display value of the ability. This is so that they all line up
// neatly in the object editor.
//
// The third paramiter is the actual value the bonus ability applys.
//
// Note that you should copy this in to its own trigger, save once, close the map and re-open
// it in the World Editor, then disable the trigger you copied this in to. If you do not
// disable the trigger, saving will take an insane ammount of time every time you save. If you
// make any changes below, you can simply enable the trigger again, save again, then disable
// the trigger again.

// BonusMod - Armor
//============================================================================================
//! textmacro ArmorAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AId1 $RAWCODE$ Idef 1 $VALUE$ anam "BonusMod - Armor ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNHumanArmorUpOne.blp
//! endtextmacro

//! runtextmacro ArmorAbility("ZxA0", "+0001", "1")
//! runtextmacro ArmorAbility("ZxA1", "+0002", "2")
//! runtextmacro ArmorAbility("ZxA2", "+0004", "4")
//! runtextmacro ArmorAbility("ZxA3", "+0008", "8")
//! runtextmacro ArmorAbility("ZxA4", "+0016", "16")
//! runtextmacro ArmorAbility("ZxA5", "+0032", "32")
//! runtextmacro ArmorAbility("ZxA6", "+0064", "64")
//! runtextmacro ArmorAbility("ZxA7", "+0128", "128")
//! runtextmacro ArmorAbility("ZxA8", "+0256", "256")
//! runtextmacro ArmorAbility("ZxA9", "+0512", "512")
//! runtextmacro ArmorAbility("ZxAa", "+1024", "1024")
//! runtextmacro ArmorAbility("ZxAb", "+2048", "2048")
//! runtextmacro ArmorAbility("ZxAc", "-4096", "-4096")

// BonusMod - Damage
//============================================================================================
//! textmacro DamageAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AItg $RAWCODE$ Iatt 1 $VALUE$ anam "BonusMod - Damage ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNSteelMelee.blp
//! endtextmacro

//! runtextmacro DamageAbility("ZxB0", "+0001", "1")
//! runtextmacro DamageAbility("ZxB1", "+0002", "2")
//! runtextmacro DamageAbility("ZxB2", "+0004", "4")
//! runtextmacro DamageAbility("ZxB3", "+0008", "8")
//! runtextmacro DamageAbility("ZxB4", "+0016", "16")
//! runtextmacro DamageAbility("ZxB5", "+0032", "32")
//! runtextmacro DamageAbility("ZxB6", "+0064", "64")
//! runtextmacro DamageAbility("ZxB7", "+0128", "128")
//! runtextmacro DamageAbility("ZxB8", "+0256", "256")
//! runtextmacro DamageAbility("ZxB9", "+0512", "512")
//! runtextmacro DamageAbility("ZxBa", "+1024", "1024")
//! runtextmacro DamageAbility("ZxBb", "+2048", "2048")
//! runtextmacro DamageAbility("ZxBc", "-4096", "-4096")

// BonusMod - Sight Range
//============================================================================================
//! textmacro SightRangeAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIsi $RAWCODE$ Isib 1 $VALUE$ anam "BonusMod - Sight Range ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNTelescope.blp
//! endtextmacro

//! runtextmacro SightRangeAbility("ZxC0", "+0001", "1")
//! runtextmacro SightRangeAbility("ZxC1", "+0002", "2")
//! runtextmacro SightRangeAbility("ZxC2", "+0004", "4")
//! runtextmacro SightRangeAbility("ZxC3", "+0008", "8")
//! runtextmacro SightRangeAbility("ZxC4", "+0016", "16")
//! runtextmacro SightRangeAbility("ZxC5", "+0032", "32")
//! runtextmacro SightRangeAbility("ZxC6", "+0064", "64")
//! runtextmacro SightRangeAbility("ZxC7", "+0128", "128")
//! runtextmacro SightRangeAbility("ZxC8", "+0256", "256")
//! runtextmacro SightRangeAbility("ZxC9", "+0512", "512")
//! runtextmacro SightRangeAbility("ZxCa", "+1024", "1024")
//! runtextmacro SightRangeAbility("ZxCb", "+2048", "2048")
//! runtextmacro SightRangeAbility("ZxCc", "-4096", "-4096")

// BonusMod - Mana Regeneration
//============================================================================================
//! textmacro ManaRegenAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIrm $RAWCODE$ Imrp 1 $VALUE$ anam "BonusMod - Mana Regen ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNSobiMask.blp
//! endtextmacro

//! runtextmacro ManaRegenAbility("ZxD0", "+0001", "0.01")
//! runtextmacro ManaRegenAbility("ZxD1", "+0002", "0.02")
//! runtextmacro ManaRegenAbility("ZxD2", "+0004", "0.04")
//! runtextmacro ManaRegenAbility("ZxD3", "+0008", "0.08")
//! runtextmacro ManaRegenAbility("ZxD4", "+0016", "0.16")
//! runtextmacro ManaRegenAbility("ZxD5", "+0032", "0.32")
//! runtextmacro ManaRegenAbility("ZxD6", "+0064", "0.64")
//! runtextmacro ManaRegenAbility("ZxD7", "+0128", "1.28")
//! runtextmacro ManaRegenAbility("ZxD8", "+0256", "2.56")
//! runtextmacro ManaRegenAbility("ZxD9", "+0512", "5.12")
//! runtextmacro ManaRegenAbility("ZxDa", "+1024", "10.24")
//! runtextmacro ManaRegenAbility("ZxDb", "+2048", "20.48")
//! runtextmacro ManaRegenAbility("ZxDc", "-4096", "-40.96")

// BonusMod - Life Regenration
//============================================================================================
//! textmacro LifeRegenAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a Arel $RAWCODE$ Ihpr 1 $VALUE$ anam "BonusMod - Life Regen ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNRingSkull.blp
//! endtextmacro

//! runtextmacro LifeRegenAbility("ZxE0", "+0001", "1")
//! runtextmacro LifeRegenAbility("ZxE1", "+0002", "2")
//! runtextmacro LifeRegenAbility("ZxE2", "+0004", "4")
//! runtextmacro LifeRegenAbility("ZxE3", "+0008", "8")
//! runtextmacro LifeRegenAbility("ZxE4", "+0016", "16")
//! runtextmacro LifeRegenAbility("ZxE5", "+0032", "32")
//! runtextmacro LifeRegenAbility("ZxE6", "+0064", "64")
//! runtextmacro LifeRegenAbility("ZxE7", "+0128", "128")
//! runtextmacro LifeRegenAbility("ZxE8", "+0256", "256")
//! runtextmacro LifeRegenAbility("ZxE9", "+0512", "512")
//! runtextmacro LifeRegenAbility("ZxEa", "+1024", "1024")
//! runtextmacro LifeRegenAbility("ZxEb", "+2048", "2048")
//! runtextmacro LifeRegenAbility("ZxEc", "-4096", "-4096")

// BonusMod - Strength
//============================================================================================
//! textmacro HeroStrAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIa1 $RAWCODE$ Iagi 1 0 Iint 1 0 Istr 1 $VALUE$ anam "BonusMod - Hero STR ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNGoldRing.blp
//! endtextmacro

//! runtextmacro HeroStrAbility("ZxF0", "+0001", "1")
//! runtextmacro HeroStrAbility("ZxF1", "+0002", "2")
//! runtextmacro HeroStrAbility("ZxF2", "+0004", "4")
//! runtextmacro HeroStrAbility("ZxF3", "+0008", "8")
//! runtextmacro HeroStrAbility("ZxF4", "+0016", "16")
//! runtextmacro HeroStrAbility("ZxF5", "+0032", "32")
//! runtextmacro HeroStrAbility("ZxF6", "+0064", "64")
//! runtextmacro HeroStrAbility("ZxF7", "+0128", "128")
//! runtextmacro HeroStrAbility("ZxF8", "+0256", "256")
//! runtextmacro HeroStrAbility("ZxF9", "+0512", "512")
//! runtextmacro HeroStrAbility("ZxFa", "+1024", "1024")
//! runtextmacro HeroStrAbility("ZxFb", "+2048", "2048")
//! runtextmacro HeroStrAbility("ZxFc", "-4096", "-4096")

// BonusMod - Agility
//============================================================================================
//! textmacro HeroAgiAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIa1 $RAWCODE$ Iagi 1 $VALUE$ Iint 1 0 Istr 1 0 anam "BonusMod - Hero AGI ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNGoldRing.blp
//! endtextmacro

//! runtextmacro HeroAgiAbility("ZxG0", "+0001", "1")
//! runtextmacro HeroAgiAbility("ZxG1", "+0002", "2")
//! runtextmacro HeroAgiAbility("ZxG2", "+0004", "4")
//! runtextmacro HeroAgiAbility("ZxG3", "+0008", "8")
//! runtextmacro HeroAgiAbility("ZxG4", "+0016", "16")
//! runtextmacro HeroAgiAbility("ZxG5", "+0032", "32")
//! runtextmacro HeroAgiAbility("ZxG6", "+0064", "64")
//! runtextmacro HeroAgiAbility("ZxG7", "+0128", "128")
//! runtextmacro HeroAgiAbility("ZxG8", "+0256", "256")
//! runtextmacro HeroAgiAbility("ZxG9", "+0512", "512")
//! runtextmacro HeroAgiAbility("ZxGa", "+1024", "1024")
//! runtextmacro HeroAgiAbility("ZxGb", "+2048", "2048")
//! runtextmacro HeroAgiAbility("ZxGc", "-4096", "-4096")

// BonusMod - Intelligence
//============================================================================================
//! textmacro HeroIntAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIa1 $RAWCODE$ Iagi 1 0 Iint 1 $VALUE$ Istr 1 0 anam "BonusMod - Hero INT ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNGoldRing.blp
//! endtextmacro

//! runtextmacro HeroIntAbility("ZxH0", "+0001", "1")
//! runtextmacro HeroIntAbility("ZxH1", "+0002", "2")
//! runtextmacro HeroIntAbility("ZxH2", "+0004", "4")
//! runtextmacro HeroIntAbility("ZxH3", "+0008", "8")
//! runtextmacro HeroIntAbility("ZxH4", "+0016", "16")
//! runtextmacro HeroIntAbility("ZxH5", "+0032", "32")
//! runtextmacro HeroIntAbility("ZxH6", "+0064", "64")
//! runtextmacro HeroIntAbility("ZxH7", "+0128", "128")
//! runtextmacro HeroIntAbility("ZxH8", "+0256", "256")
//! runtextmacro HeroIntAbility("ZxH9", "+0512", "512")
//! runtextmacro HeroIntAbility("ZxHa", "+1024", "1024")
//! runtextmacro HeroIntAbility("ZxHb", "+2048", "2048")
//! runtextmacro HeroIntAbility("ZxHc", "-4096", "-4096")

// Don't let a //! external command be the last line in a trigger!

JASS:
// The Mana ability:
//! external ObjectMerger w3a AImz Zx00 alev 19 aite 0 Iman 1 0 Iman 2 1 Iman 3 2 Iman 4 4 Iman 5 8 Iman 6 16 Iman 7 32 Iman 8 64 Iman 9 128 Iman 10 256 Iman 11 -1 Iman 12 -2 Iman 13 -4 Iman 14 -8 Iman 15 -16 Iman 16 -32 Iman 17 -64 Iman 18 -128 Iman 19 -256 anam "SetUnitMaxState - Mana" ansf "" aart ReplaceableTextures\CommandButtons\BTNManaStone.blp

// The Life ability:
//! external ObjectMerger w3a AIlf Zx01 alev 19 aite 0 Ilif 1 0 Ilif 2 1 Ilif 3 2 Ilif 4 4 Ilif 5 8 Ilif 6 16 Ilif 7 32 Ilif 8 64 Ilif 9 128 Ilif 10 256 Ilif 11 -1 Ilif 12 -2 Ilif 13 -4 Ilif 14 -8 Ilif 15 -16 Ilif 16 -32 Ilif 17 -64 Ilif 18 -128 Ilif 19 -256 anam "SetUnitMaxState - Life" ansf "" aart ReplaceableTextures\CommandButtons\BTNHealthStone.blp

// Don't let a //! external command be the last line in a trigger!

Note that if your map contains abilities which have rawcodes containing Zx followed by an upper-case letter, you will have some trouble with implementing this system. To easy implementation, use the Find and Replace function included in the JASS NewGen trigger editor to replace all occurrences of Zx in the above macros, as well as in each systems library.

The Libraries
JASS:
//////////////////////////////////////////////////////////////////////////////////////////
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@     Bonus Mod
//@=======================================================================================
//@ Credits:
//@---------------------------------------------------------------------------------------
//@     Written by:
//@         Earth-Fury
//@     Based on the work of:
//@         weaaddar
//@
//@ If you use this system, please credit all of the people mentioned above in your map.
//@=======================================================================================
//@ Bonus Mod Readme
//@---------------------------------------------------------------------------------------
//@ 
//@ BonusMod is a system for adding bonuses to a single unit. For example, you may wish
//@ to add a +40 damage bonus, or a -3 armor 'bonus'. Bonus mod works by adding abilitys
//@ to a unit which effect the particular stat by a power of two. By combining diffrent
//@ powers of two, you can reach any number between 0 and 2^(n+1) - 1, where n is the
//@ largest power of 2 used. Bonus mod can also apply negative bonuses, by adding an
//@ ability which has a 'bonus' of -2^(n+1), where again, n is the maximum power of 2.
//@ With the negative bonus, you can add anywhere between 1 and 2^(n+1)-1 of a bonus. This
//@ gives bonus mod a range of bonuses between -2^(n+1) and 2^(n+1)-1. By default, n is
//@ set at 11, giving us a range of bonuses between -4096 and +4095.
//@
//@---------------------------------------------------------------------------------------
//@ Adding Bonus Mod to your map:
//@
//@ Copy this library in to a trigger named "BonusMod" in your map.
//@
//@ After the script is copied, the hard part begins. You will have to transfer all of the
//@ bonus abilitys found in this map to yours. However, this is really easy to do if you
//@ are using the JASS NewGen editor. (Which you will have to be anyway, considering this
//@ system is written in vJASS.) Included with this library are macros for the Object 
//@ Merger included in NewGen. Simply copy the Object Merger script included with this 
//@ system in to your map in its own trigger. Save your map. (Saving will take a while. 
//@ Up to 5 min if you have a slow computer.) Close your map, and reopen it. Disable the 
//@ trigger you copied the ObjectMerger script in to.
//@ Your map now has all the abilitys it needs!
//@
//@---------------------------------------------------------------------------------------
//@ Functions:
//@
//@ boolean UnitSetBonus(unit <target unit>, integer <bonus type>, integer <bonus ammount>)
//@ 
//@     This function clears any previously applied bonus on <target unit>, setting the 
//@ unit's bonus for <bonus type> to <bonus ammount>. <bonus type> should be one of the
//@ integer type constants below. This function will return false if the desired bonus is
//@ not a valid bonus type, or out of the range of bonuses that can be applied.
//@
//@ integer UnitGetBonus(unit <target unit>, integer <bonus type>)
//@ 
//@     Returns the bonus ammount of <bonus type> currently applied to <target unit>.
//@
//@ boolean UnitAddBonus(unit <target unit>, integer <bonus type>, integer <bonus ammount>)
//@
//@     This function will add <bonus ammount> to the bonus of type <bonus type> on the
//@ unit <target unit>. <bonus ammount> can be a negative value. This function will return
//@ false if the new bonus will be out of the range which bonus mod can apply.
//@
//@ nothing UnitClearBonus(unit <target unit>, integer <bonus type>)
//@
//@     This function will effectively set the bonus of type <bonus type> for the unit
//@ <target unit> to 0. It is advised you use this function over UnitSetBonus(..., ..., 0)
//@
//@---------------------------------------------------------------------------------------
//@ Variables:
//@ 
//@ BonusMod_MaxBonus
//@     The maximum bonus that Bonus Mod can apply
//@ BonusMod_MinBonus
//@     The minimum bonus that Bonus Mod can apply
//@---------------------------------------------------------------------------------------
//@ Increasing the Range of Bonuses:
//@
//@ By default, bonus mod uses 13 abilitys per bonus type. This gives each bonus type a
//@ range of -4096 to +4095. To increase this range, you will have to create one new
//@ ability for each ability, for each power of two you increase bonus mod by. You will
//@ also have to edit the negative bonus ability to apply a bonus of -2^(n+1), where n is
//@ the largest power of two you will be using for positive bonuses. You will need to edit
//@ the ABILITY_COUNT constant found below to reflect the new total number of abilitys
//@ each individual bonus will use. You will also have to add the abilitys to the function
//@ InitializeAbilitys. Note that the number in the array index indicates which power of
//@ 2 is held there. So, for instance, set BonusAbilitys[i + 15] would hold an ability
//@ which changes the relivent stat by 32768. (2^15 = 32768) The last ability in the array
//@ must apply a negative bonus.
//@
//@ Here is an example of the bonus BONUS_ARMOR using 15 abilitys instead of 12:
//@
//@    set i = BONUS_ARMOR * ABILITY_COUNT
//@    set BonusAbilitys[i + 0]  = 'ZxA0' // +1
//@    set BonusAbilitys[i + 1]  = 'ZxA1' // +2
//@    set BonusAbilitys[i + 2]  = 'ZxA2' // +4
//@    set BonusAbilitys[i + 3]  = 'ZxA3' // +8
//@    set BonusAbilitys[i + 4]  = 'ZxA4' // +16
//@    set BonusAbilitys[i + 5]  = 'ZxA5' // +32
//@    set BonusAbilitys[i + 6]  = 'ZxA6' // +64
//@    set BonusAbilitys[i + 7]  = 'ZxA7' // +128
//@    set BonusAbilitys[i + 8]  = 'ZxA8' // +256
//@    set BonusAbilitys[i + 9]  = 'ZxA9' // +512
//@    set BonusAbilitys[i + 10] = 'ZxAa' // +1024
//@    set BonusAbilitys[i + 11] = 'ZxAb' // +2048
//@    set BonusAbilitys[i + 12] = 'ZxAc' // +4096
//@    set BonusAbilitys[i + 13] = 'ZxAd' // +8192
//@    set BonusAbilitys[i + 14] = 'ZxAe' // +16384
//@    set BonusAbilitys[i + 15] = 'ZxAf' // -32768
//@
//@---------------------------------------------------------------------------------------
//@ Adding and Removing Bonus Types:
//@
//@ Removing a bonus type is simple. First, delete it from the list of constants found
//@ below. Make sure the constants are numberd 0, 1, 2, 3, etc. without any gaps. Change
//@ the BONUS_TYPES constant to reflect the new number of bonuses. You must then remove
//@ the lines of array initialization for the bonus you removed from the
//@ InitializeAbilitys function. You can then delete the abilitys for that bonus type, and
//@ you are then done removing a bonus type.
//@
//@ Adding a bonus type is done in much the same way. Add a constant for it to the list of
//@ constants below, ensuring they are numberd 0, 1, 2, 3 etc. withour any gaps. Change
//@ the BONUS_TYPES constant to reflect the new number of bonuses. You must then create
//@ all the needed abilitys for the new bonus type. Ensure the bonus they each apply is a
//@ power of 2, as with the already included bonuses. See the section Increasing the Range
//@ of Bonuses for more information. After all the abilitys are added, you must add the
//@ needed lines to the InitializeAbilitys function. The existing lines should be a clear
//@ enogh example.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//////////////////////////////////////////////////////////////////////////////////////////
library BonusMod initializer Initialize

globals
//========================================================================================
// Bonus Type Constants
//========================================================================================

    constant integer BONUS_ARMOR            = 0 // Armor Bonus
    constant integer BONUS_DAMAGE           = 1 // Damage Bonus
    constant integer BONUS_SIGHT_RANGE      = 2 // Sight Range Bonus
    constant integer BONUS_MANA_REGEN       = 3 // Mana Regeneration Bonus (A % value)
    constant integer BONUS_LIFE_REGEN       = 4 // Life Regeneration Bonus (An absolute value)
    constant integer BONUS_HERO_STR         = 5 // Strength Bonus
    constant integer BONUS_HERO_AGI         = 6 // Agility Bonus
    constant integer BONUS_HERO_INT         = 7 // Intelligence Bonus

    // The number of bonus type constants above:
    constant integer BONUS_TYPES = 8 

//========================================================================================
// Other Configuration
//========================================================================================

    // The number of abilitys used per bonus type:
    private constant integer ABILITY_COUNT = 13
    
    // Note: Setting the following to false will decrease loading time, but will cause a
    // small ammount of lag when a bonus is first applied. (Especially a negative bonus)
    // If set to true, all BonusMod abilitys will be preloaded:
    private constant boolean PRELOAD_ABILITYS = true
    
    // Only applies if PRELOAD_ABILITYS is set to true.
    // The unit type used to preload abilitys on:
    private constant integer PRELOAD_DUMMY_UNIT = 'hpea'
endglobals

//========================================================================================
// Ability Initialization
//----------------------------------------------------------------------------------------
// The following function is used to define the rawcodes for all the abilitys bonus mod
// uses. If you use the text macros included with BonusMod, and if you do not wish to add,
// remove, or change the range of bonuses, you will not have to edit the following.
// 
// Note that if your map already has abilitys with rawcodes that begin with Zx followed by
// an upper-case letter, the ObjectMerger macros included with this library will not work
// and you will have to edit the lines below. However, you could use the find and replace
// feature in JASS NewGen's Trigger Editor Syntax Highlighter to replace all occurances of
// Zx both here and in the ObjectMerger macros to ease configuration.
//========================================================================================
private keyword BonusAbilitys
private function InitializeAbilitys takes nothing returns nothing
    local integer i

    // Bonus Mod - Armor abilitys
    set i = BONUS_ARMOR * ABILITY_COUNT
    set BonusAbilitys[i + 0]  = 'ZxA0' // +1
    set BonusAbilitys[i + 1]  = 'ZxA1' // +2
    set BonusAbilitys[i + 2]  = 'ZxA2' // +4
    set BonusAbilitys[i + 3]  = 'ZxA3' // +8
    set BonusAbilitys[i + 4]  = 'ZxA4' // +16
    set BonusAbilitys[i + 5]  = 'ZxA5' // +32
    set BonusAbilitys[i + 6]  = 'ZxA6' // +64
    set BonusAbilitys[i + 7]  = 'ZxA7' // +128
    set BonusAbilitys[i + 8]  = 'ZxA8' // +256
    set BonusAbilitys[i + 9]  = 'ZxA9' // +512
    set BonusAbilitys[i + 10] = 'ZxAa' // +1024
    set BonusAbilitys[i + 11] = 'ZxAb' // +2048
    set BonusAbilitys[i + 12] = 'ZxAc' // -4096
    
    // Bonus Mod - Damage abilitys
    set i = BONUS_DAMAGE * ABILITY_COUNT
    set BonusAbilitys[i + 0]  = 'ZxB0' // +1
    set BonusAbilitys[i + 1]  = 'ZxB1' // +2
    set BonusAbilitys[i + 2]  = 'ZxB2' // +4
    set BonusAbilitys[i + 3]  = 'ZxB3' // +8
    set BonusAbilitys[i + 4]  = 'ZxB4' // +16
    set BonusAbilitys[i + 5]  = 'ZxB5' // +32
    set BonusAbilitys[i + 6]  = 'ZxB6' // +64
    set BonusAbilitys[i + 7]  = 'ZxB7' // +128
    set BonusAbilitys[i + 8]  = 'ZxB8' // +256
    set BonusAbilitys[i + 9]  = 'ZxB9' // +512
    set BonusAbilitys[i + 10] = 'ZxBa' // +1024
    set BonusAbilitys[i + 11] = 'ZxBb' // +2048
    set BonusAbilitys[i + 12] = 'ZxBc' // -4096
    
    // Bonus Mod - Sight Range abilitys
    set i = BONUS_SIGHT_RANGE * ABILITY_COUNT
    set BonusAbilitys[i + 0]  = 'ZxC0' // +1
    set BonusAbilitys[i + 1]  = 'ZxC1' // +2
    set BonusAbilitys[i + 2]  = 'ZxC2' // +4
    set BonusAbilitys[i + 3]  = 'ZxC3' // +8
    set BonusAbilitys[i + 4]  = 'ZxC4' // +16
    set BonusAbilitys[i + 5]  = 'ZxC5' // +32
    set BonusAbilitys[i + 6]  = 'ZxC6' // +64
    set BonusAbilitys[i + 7]  = 'ZxC7' // +128
    set BonusAbilitys[i + 8]  = 'ZxC8' // +256
    set BonusAbilitys[i + 9]  = 'ZxC9' // +512
    set BonusAbilitys[i + 10] = 'ZxCa' // +1024
    set BonusAbilitys[i + 11] = 'ZxCb' // +2048
    set BonusAbilitys[i + 12] = 'ZxCc' // -4096
    
    // Bonus Mod - Mana Regen abilitys
    set i = BONUS_MANA_REGEN * ABILITY_COUNT
    set BonusAbilitys[i + 0]  = 'ZxD0' // +1
    set BonusAbilitys[i + 1]  = 'ZxD1' // +2
    set BonusAbilitys[i + 2]  = 'ZxD2' // +4
    set BonusAbilitys[i + 3]  = 'ZxD3' // +8
    set BonusAbilitys[i + 4]  = 'ZxD4' // +16
    set BonusAbilitys[i + 5]  = 'ZxD5' // +32
    set BonusAbilitys[i + 6]  = 'ZxD6' // +64
    set BonusAbilitys[i + 7]  = 'ZxD7' // +128
    set BonusAbilitys[i + 8]  = 'ZxD8' // +256
    set BonusAbilitys[i + 9]  = 'ZxD9' // +512
    set BonusAbilitys[i + 10] = 'ZxDa' // +1024
    set BonusAbilitys[i + 11] = 'ZxDb' // +2048
    set BonusAbilitys[i + 12] = 'ZxDc' // -4096
    
    // Bonus Mod - Life Regen abilitys
    set i = BONUS_LIFE_REGEN * ABILITY_COUNT
    set BonusAbilitys[i + 0]  = 'ZxE0' // +1
    set BonusAbilitys[i + 1]  = 'ZxE1' // +2
    set BonusAbilitys[i + 2]  = 'ZxE2' // +4
    set BonusAbilitys[i + 3]  = 'ZxE3' // +8
    set BonusAbilitys[i + 4]  = 'ZxE4' // +16
    set BonusAbilitys[i + 5]  = 'ZxE5' // +32
    set BonusAbilitys[i + 6]  = 'ZxE6' // +64
    set BonusAbilitys[i + 7]  = 'ZxE7' // +128
    set BonusAbilitys[i + 8]  = 'ZxE8' // +256
    set BonusAbilitys[i + 9]  = 'ZxE9' // +512
    set BonusAbilitys[i + 10] = 'ZxEa' // +1024
    set BonusAbilitys[i + 11] = 'ZxEb' // +2048
    set BonusAbilitys[i + 12] = 'ZxEc' // -4096
    
    // Bonus Mod - Hero STR abilitys
    set i = BONUS_HERO_STR * ABILITY_COUNT
    set BonusAbilitys[i + 0]  = 'ZxF0' // +1
    set BonusAbilitys[i + 1]  = 'ZxF1' // +2
    set BonusAbilitys[i + 2]  = 'ZxF2' // +4
    set BonusAbilitys[i + 3]  = 'ZxF3' // +8
    set BonusAbilitys[i + 4]  = 'ZxF4' // +16
    set BonusAbilitys[i + 5]  = 'ZxF5' // +32
    set BonusAbilitys[i + 6]  = 'ZxF6' // +64
    set BonusAbilitys[i + 7]  = 'ZxF7' // +128
    set BonusAbilitys[i + 8]  = 'ZxF8' // +256
    set BonusAbilitys[i + 9]  = 'ZxF9' // +512
    set BonusAbilitys[i + 10] = 'ZxFa' // +1024
    set BonusAbilitys[i + 11] = 'ZxFb' // +2048
    set BonusAbilitys[i + 12] = 'ZxFc' // -4096
    
    // Bonus Mod - Hero AGI abilitys
    set i = BONUS_HERO_AGI * ABILITY_COUNT
    set BonusAbilitys[i + 0]  = 'ZxG0' // +1
    set BonusAbilitys[i + 1]  = 'ZxG1' // +2
    set BonusAbilitys[i + 2]  = 'ZxG2' // +4
    set BonusAbilitys[i + 3]  = 'ZxG3' // +8
    set BonusAbilitys[i + 4]  = 'ZxG4' // +16
    set BonusAbilitys[i + 5]  = 'ZxG5' // +32
    set BonusAbilitys[i + 6]  = 'ZxG6' // +64
    set BonusAbilitys[i + 7]  = 'ZxG7' // +128
    set BonusAbilitys[i + 8]  = 'ZxG8' // +256
    set BonusAbilitys[i + 9]  = 'ZxG9' // +512
    set BonusAbilitys[i + 10] = 'ZxGa' // +1024
    set BonusAbilitys[i + 11] = 'ZxGb' // +2048
    set BonusAbilitys[i + 12] = 'ZxGc' // -4096
    
    // Bonus Mod - Hero INT abilitys
    set i = BONUS_HERO_INT * ABILITY_COUNT
    set BonusAbilitys[i + 0]  = 'ZxH0' // +1
    set BonusAbilitys[i + 1]  = 'ZxH1' // +2
    set BonusAbilitys[i + 2]  = 'ZxH2' // +4
    set BonusAbilitys[i + 3]  = 'ZxH3' // +8
    set BonusAbilitys[i + 4]  = 'ZxH4' // +16
    set BonusAbilitys[i + 5]  = 'ZxH5' // +32
    set BonusAbilitys[i + 6]  = 'ZxH6' // +64
    set BonusAbilitys[i + 7]  = 'ZxH7' // +128
    set BonusAbilitys[i + 8]  = 'ZxH8' // +256
    set BonusAbilitys[i + 9]  = 'ZxH9' // +512
    set BonusAbilitys[i + 10] = 'ZxHa' // +1024
    set BonusAbilitys[i + 11] = 'ZxHb' // +2048
    set BonusAbilitys[i + 12] = 'ZxHc' // -4096
endfunction

//========================================================================================
// System Code
//----------------------------------------------------------------------------------------
// Do not edit below this line unless you wish to change the way the system works.
//========================================================================================

globals
    // Contains all abilitys in a two-dimensional structure:
    private integer array BonusAbilitys
    
    // Precomputed powers of two to avoid speed and rounding issues with Pow():
    private integer array PowersOf2

    // Range constants (Read only please):
    public integer MaxBonus
    public integer MinBonus
endglobals

function UnitClearBonus takes unit u, integer bonusType returns nothing
    local integer i = 0
    
    loop
        call UnitRemoveAbility(u, BonusAbilitys[bonusType * ABILITY_COUNT + i])
        
        set i = i + 1
        exitwhen i == ABILITY_COUNT - 2
    endloop
endfunction

function UnitSetBonus takes unit u, integer bonusType, integer ammount returns boolean
    local integer i = ABILITY_COUNT - 2
    
    if ammount < MinBonus or ammount > MaxBonus then
        debug call BJDebugMsg("BonusSystem Error: Bonus too high or low (" + I2S(ammount) + ")")
        return false
    elseif bonusType < 0 or bonusType >= BONUS_TYPES then
        debug call BJDebugMsg("BonusSystem Error: Invalid bonus type (" + I2S(bonusType) + ")")
        return false
    endif
    
    if ammount < 0 then
        set ammount = MaxBonus + ammount + 1
        call UnitAddAbility(u, BonusAbilitys[bonusType * ABILITY_COUNT + ABILITY_COUNT - 1])
        call UnitMakeAbilityPermanent(u, true, BonusAbilitys[bonusType * ABILITY_COUNT + ABILITY_COUNT - 1])
    else
        call UnitRemoveAbility(u, BonusAbilitys[bonusType * ABILITY_COUNT + ABILITY_COUNT - 1])
    endif

    loop
        if ammount >= PowersOf2[i] then
            call UnitAddAbility(u, BonusAbilitys[bonusType * ABILITY_COUNT + i])
            call UnitMakeAbilityPermanent(u, true, BonusAbilitys[bonusType * ABILITY_COUNT + i])
            set ammount = ammount - PowersOf2[i]
        else
            call UnitRemoveAbility(u, BonusAbilitys[bonusType * ABILITY_COUNT + i])
        endif
        
        set i = i - 1
        exitwhen i < 0
    endloop
    
    return true
endfunction

function UnitGetBonus takes unit u, integer bonusType returns integer
    local integer i = 0
    local integer ammount = 0
    
    if GetUnitAbilityLevel(u, BonusAbilitys[bonusType * ABILITY_COUNT + ABILITY_COUNT - 1]) > 0 then
        set ammount = MinBonus
    endif
    
    loop
        if GetUnitAbilityLevel(u, BonusAbilitys[bonusType * ABILITY_COUNT + i]) > 0 then
            set ammount = ammount + PowersOf2[i]
        endif
        
        set i = i + 1
        exitwhen i == ABILITY_COUNT - 2
    endloop
    
    return ammount
endfunction

function UnitAddBonus takes unit u, integer bonusType, integer ammount returns boolean
    return UnitSetBonus(u, bonusType, UnitGetBonus(u, bonusType) + ammount)
endfunction

private function Initialize takes nothing returns nothing
    local integer i = 1
    local unit u
    
    set PowersOf2[0] = 1
    loop
        set PowersOf2[i] = PowersOf2[i - 1] * 2
        set i = i + 1
        exitwhen i == ABILITY_COUNT
    endloop
    
    set MaxBonus = PowersOf2[ABILITY_COUNT - 1] - 1
    set MinBonus = -PowersOf2[ABILITY_COUNT - 1]
    
    call InitializeAbilitys()
    
    if PRELOAD_ABILITYS then
        set u = CreateUnit(Player(15), PRELOAD_DUMMY_UNIT, 0, 0, 0)
        set i = 0
        loop
            exitwhen i == BONUS_TYPES * ABILITY_COUNT
            call UnitAddAbility(u, BonusAbilitys[i])
            set i = i + 1
        endloop
        call RemoveUnit(u)
    endif
endfunction
endlibrary
JASS:
//////////////////////////////////////////////////////////////////////////////////////////
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@     SetUnitMaxState
//@=======================================================================================
//@ Credits:
//@---------------------------------------------------------------------------------------
//@     Written by:
//@         Earth-Fury
//@     Based on the work of:
//@         Blade.dk
//@
//@ If you use this system, please credit all of the people mentioned above in your map.
//@=======================================================================================
//@ SetUnitMaxState Readme
//@---------------------------------------------------------------------------------------
//@
//@ SetUnitMaxState() is a function origionally written by Blade.dk. It takes advantage of
//@ a bug which was introduced in one of the patches: Bonus life and mana abilitys will
//@ only ever add the bonus ammount for level 1. However, when removed, they will remove
//@ the ammount they should have added at their current level. This allows you to change a
//@ units maximum life and mana, without adding a perminent ability to the unit.
//@
//@---------------------------------------------------------------------------------------
//@ Adding SetUnitMaxState to your map:
//@ 
//@ Simply copy this library in to a trigger which has been converted to custom text.
//@ After that, you must copy over the abilitys. This is made easy by the ObjectMerger in
//@ JASS NewGen. Distributed with this system are //! external calls to the ObjectMerger.
//@ Simply copy both of them in to your map, save your map, close and reopen your map in
//@ the editor, and remove the external calls. (Or otherwise disable them. Removing the !
//@ after the // works.)
//@
//@---------------------------------------------------------------------------------------
//@ Using SetUnitMaxState:
//@
//@ nothing SetUnitMaxState(unit <target>, unitstate <state>, real <new value>)
//@
//@     This function changes <target>'s unitstate <state> to be eqal to <new value>. Note
//@ that the only valid unitstates this function will use are UNIT_STATE_MAX_MAN and
//@ UNIT_STATE_MAX_LIFE. Use SetUnitState() to change other unitstates.
//@
//@ nothing AddUnitMaxState(unit <target>, unitstate <state>, real <add value>)
//@
//@     This function adds <add value> to <target>'s <state> unitstate. <add value> can be
//@ less than 0, making this function reduce the specified unitstate. This function will
//@ only work with the unitstates UNIT_STATE_MAX_LIFE and UNIT_STATE_MAX_MANA.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//////////////////////////////////////////////////////////////////////////////////////////
library SetUnitMaxState initializer Initialize
globals
//========================================================================================
// Configuration
//========================================================================================

    // The rawcode of the life ability:
    private constant integer MAX_STATE_LIFE_ABILITY = 'Zx01'
    
    // The rawcode of the mana ability:
    private constant integer MAX_STATE_MANA_ABILITY = 'Zx00'
    
    // The maximum power of two the abilitys use:
    private constant integer MAX_STATE_MAX_POWER = 8
endglobals

//========================================================================================
// System Code
//----------------------------------------------------------------------------------------
// Do not edit below this line unless you wish to change the way the system works.
//========================================================================================

globals
    private integer array PowersOf2
endglobals

function SetUnitMaxState takes unit u, unitstate state, real newValue returns nothing
    local integer stateAbility
    local integer newVal = R2I(newValue)
    local integer i = MAX_STATE_MAX_POWER
    local integer offset
    
    if state == UNIT_STATE_MAX_LIFE then
        set stateAbility = MAX_STATE_LIFE_ABILITY
    elseif state == UNIT_STATE_MAX_MANA then
        set stateAbility = MAX_STATE_MANA_ABILITY
    else
        debug call BJDebugMsg("SetUnitMaxState Error: Invalid unitstate")
        return
    endif
    
    set newVal = newVal - R2I(GetUnitState(u, state))
    
    if newVal > 0 then
        set offset = MAX_STATE_MAX_POWER + 3
    elseif newVal < 0 then
        set offset = 2
        set newVal = -newVal
    else
        return
    endif
    
    loop
        exitwhen newVal == 0 or i < 0
        if newVal >= PowersOf2[i] then
            call UnitAddAbility(u, stateAbility)
            call SetUnitAbilityLevel(u, stateAbility, offset + i)
            call UnitRemoveAbility(u, stateAbility)
            set newVal = newVal - PowersOf2[i]
        else
            set i = i - 1
        endif
    endloop
endfunction

function AddUnitMaxState takes unit u, unitstate state, real addValue returns nothing
    call SetUnitMaxState(u, state, GetUnitState(u, state) + addValue)
endfunction

private function Initialize takes nothing returns nothing
    local integer i = 1
    
    set PowersOf2[0] = 1
    loop
        set PowersOf2[i] = PowersOf2[i - 1] * 2
        set i = i + 1
        exitwhen i == MAX_STATE_MAX_POWER + 3
    endloop
endfunction
endlibrary

Credit Where Credit is Due

Bonus Mod is a system originally written by weaaddar.

SetUnitMaxState() is a function originally written by Blade.dk.

Demo Map

Because of the nature of these systems, I thought it prudent to include a small demo map. If anyone wants to make a less-sucky demo map, feel free and I'll include it in this post with credit to you. Else I will some day make a decent demo map.

Download the Demo Map: View attachment EarthFurys Bonus Mod Version 1.0.0.w3x

In Closing

Any suggestions? Criticism? Anyone willing to write better documentation?

I haven't so extensively bug-tested these systems, but they seem stable enough for a general release. If you find any bugs or have any gripes, please do speak up now.

And finally, don't criticize my crappy wrapper functions too much. I'm just too tired of staring at 500 lines of code to properly implement those two functions.
 
Level 2
Joined
Jan 29, 2009
Messages
21
This is really handy, especially since the map I'm working on has multiple levels of each ability, and often the bonuses are based off of a hero attribute, and until now doing that was impossible.

Thanks for an excellent mod :infl_thumbs_up:

EDIT #1: There does seem to be one moderate bug, if you modify strength by any negative value, the hero dies.

EDIT #2: Actually, I found another bug. Clearing doesn't work with negative values, and neither does GetUnitBonus. I fixed both of those, but still haven't been able to fix the strength problem. I believe it happens because the -4096 STR is applied before any other bonuses, I'll try to fix it.

In order to fix ClearUnitBonus and GetUnitBonus to work with negative values, you just need to switch "exitwhen i = ABILITY_COUNT - 2" in the UnitClearBonus function to "exitwhen i = ABILITY_COUNT", and "exitwhen i = ABILITY_COUNT - 2" in UnitGetBonus to "exitwhen i = ABILITY_COUNT - 1".

All in all just simple arithmetic mistakes that are easily fixed.
 
Last edited:
Level 10
Joined
Aug 19, 2008
Messages
491
Hello mates! :grin:
I made a spell out of the SetUnitMaxState() library. Works great, awesome library! :thumbs_up:
However I noticed a dumb bug in my spell: It lagged first time I used it.
So I sat down wondering why for a while, and then I realized that SetUnitMaxState() uses 2 abilities, and nowhere in the library do they preload!

So I've added a preload function, and now it works without lags. Thought I'd might share it with you.
Here's the modyfied version I use:

JASS:
//////////////////////////////////////////////////////////////////////////////////////////
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@ SetUnitMaxState
//@=======================================================================================
//@ Credits:
//@---------------------------------------------------------------------------------------
//@ Written by:
//@ Earth-Fury
//@ Based on the work of:
//@ Blade.dk
//@
//@ If you use this system, please credit all of the people mentioned above in your map.
//@=======================================================================================
//@ SetUnitMaxState Readme
//@---------------------------------------------------------------------------------------
//@
//@ SetUnitMaxState() is a function origionally written by Blade.dk. It takes advantage of
//@ a bug which was introduced in one of the patches: Bonus life and mana abilitys will
//@ only ever add the bonus ammount for level 1. However, when removed, they will remove
//@ the ammount they should have added at their current level. This allows you to change a
//@ units maximum life and mana, without adding a perminent ability to the unit.
//@
//@---------------------------------------------------------------------------------------
//@ Adding SetUnitMaxState to your map:
//@
//@ Simply copy this library in to a trigger which has been converted to custom text.
//@ After that, you must copy over the abilitys. This is made easy by the ObjectMerger in
//@ JASS NewGen. Distributed with this system are //! external calls to the ObjectMerger.
//@ Simply copy both of them in to your map, save your map, close and reopen your map in
//@ the editor, and remove the external calls. (Or otherwise disable them. Removing the !
//@ after the // works.)
//@
//@---------------------------------------------------------------------------------------
//@ Using SetUnitMaxState:
//@
//@ nothing SetUnitMaxState(unit <target>, unitstate <state>, real <new value>)
//@
//@ This function changes <target>'s unitstate <state> to be eqal to <new value>. Note
//@ that the only valid unitstates this function will use are UNIT_STATE_MAX_MAN and
//@ UNIT_STATE_MAX_LIFE. Use SetUnitState() to change other unitstates.
//@
//@ nothing AddUnitMaxState(unit <target>, unitstate <state>, real <add value>)
//@
//@ This function adds <add value> to <target>'s <state> unitstate. <add value> can be
//@ less than 0, making this function reduce the specified unitstate. This function will
//@ only work with the unitstates UNIT_STATE_MAX_LIFE and UNIT_STATE_MAX_MANA.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//////////////////////////////////////////////////////////////////////////////////////////
library SetUnitMaxState initializer Initialize
    globals
//========================================================================================
// Configuration
//========================================================================================

        // The rawcode of the life ability:
        private constant integer MAX_STATE_LIFE_ABILITY = 'Zx01'

        // The rawcode of the mana ability:
        private constant integer MAX_STATE_MANA_ABILITY = 'Zx00'

        // The maximum power of two the abilitys use:
        private constant integer MAX_STATE_MAX_POWER = 8
        
        //The dummy unit of your map
        private constant integer DUMMY_ID = 'h000'

//========================================================================================
// System Code
//----------------------------------------------------------------------------------------
// Do not edit below this line unless you wish to change the way the system works.
//========================================================================================
    endglobals


    globals
        private integer array PowersOf2
    endglobals

    function SetUnitMaxState takes unit u, unitstate state, real newValue returns nothing
        local integer stateAbility
        local integer newVal = R2I(newValue)
        local integer i = MAX_STATE_MAX_POWER
        local integer offset

        if state == UNIT_STATE_MAX_LIFE then
            set stateAbility = MAX_STATE_LIFE_ABILITY
        elseif state == UNIT_STATE_MAX_MANA then
            set stateAbility = MAX_STATE_MANA_ABILITY
        else
            debug call BJDebugMsg("SetUnitMaxState Error: Invalid unitstate")
            return
        endif

        set newVal = newVal - R2I(GetUnitState(u, state))

        if newVal > 0 then
            set offset = MAX_STATE_MAX_POWER + 3
        elseif newVal < 0 then
            set offset = 2
            set newVal = -newVal
        else
            return
        endif

        loop
            exitwhen newVal == 0 or i < 0
            if newVal >= PowersOf2[i] then
                call UnitAddAbility(u, stateAbility)
                call SetUnitAbilityLevel(u, stateAbility, offset + i)
                call UnitRemoveAbility(u, stateAbility)
                set newVal = newVal - PowersOf2[i]
            else
                set i = i - 1
            endif
        endloop
    endfunction

    function AddUnitMaxState takes unit u, unitstate state, real addValue returns nothing
        call SetUnitMaxState(u, state, GetUnitState(u, state) + addValue)
    endfunction

    private function Initialize takes nothing returns nothing
        local integer i = 1

        set PowersOf2[0] = 1
        loop
            set PowersOf2[i] = PowersOf2[i - 1] * 2
            set i = i + 1
            exitwhen i == MAX_STATE_MAX_POWER + 3
        endloop
        
        set bj_lastCreatedUnit = CreateUnit( Player( PLAYER_NEUTRAL_PASSIVE ), DUMMY_ID, 0., 0., 0. )
        call UnitAddAbility( bj_lastCreatedUnit, MAX_STATE_LIFE_ABILITY )
        call UnitAddAbility( bj_lastCreatedUnit, MAX_STATE_MANA_ABILITY )
        call KillUnit( bj_lastCreatedUnit )
    endfunction
endlibrary

Hope you enjoy this improvment! :grin:

Oh and, before I get any stupid comments, note that I use bj_lastCreatedUnit because it's faster than a local variable.
Yes, bj_ variables are faster than regular, while BJ functions are slower.
Now you know, hope that come in handy aswell.
 
Last edited:
Added attackspeed and movespeed!


JASS:
//////////////////////////////////////////////////////////////////////////////////////////
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@ Bonus Mod
//@=======================================================================================
//@ Credits:
//@---------------------------------------------------------------------------------------
//@ Written by:
//@  dhk_undead_lord aka Anachron
//@ Based on the work of:
//@  Earth-Fury
//@  weaaddar
//@
//@ If you use this system, please credit all of the people mentioned above in your map.
//@=======================================================================================
//@ Bonus Mod Readme
//@---------------------------------------------------------------------------------------
//@
//@ BonusMod is a system for adding bonuses to a single unit. For example, you may wish
//@ to add a +40 damage bonus, or a -3 armor 'bonus'. Bonus mod works by adding abilitys
//@ to a unit which effect the particular stat by a power of two. By combining diffrent
//@ powers of two, you can reach any number between 0 and 2^(n+1) - 1, where n is the
//@ largest power of 2 used. Bonus mod can also apply negative bonuses, by adding an
//@ ability which has a 'bonus' of -2^(n+1), where again, n is the maximum power of 2.
//@ With the negative bonus, you can add anywhere between 1 and 2^(n+1)-1 of a bonus. This
//@ gives bonus mod a range of bonuses between -2^(n+1) and 2^(n+1)-1. By default, n is
//@ set at 11, giving us a range of bonuses between -4096 and +4095.
//@
//@---------------------------------------------------------------------------------------
//@ Adding Bonus Mod to your map:
//@
//@ Copy this library in to a trigger named "BonusMod" in your map.
//@
//@ After the script is copied, the hard part begins. You will have to transfer all of the
//@ bonus abilitys found in this map to yours. However, this is really easy to do if you
//@ are using the JASS NewGen editor. (Which you will have to be anyway, considering this
//@ system is written in vJASS.) Included with this library are macros for the Object
//@ Merger included in NewGen. Simply copy the Object Merger script included with this
//@ system in to your map in its own trigger. Save your map. (Saving will take a while.
//@ Up to 5 min if you have a slow computer.) Close your map, and reopen it. Disable the
//@ trigger you copied the ObjectMerger script in to.
//@ Your map now has all the abilitys it needs!
//@
//@---------------------------------------------------------------------------------------
//@ Functions:
//@
//@ boolean UnitSetBonus(unit <target unit>, integer <bonus type>, integer <bonus ammount>)
//@
//@ This function clears any previously applied bonus on <target unit>, setting the
//@ unit's bonus for <bonus type> to <bonus ammount>. <bonus type> should be one of the
//@ integer type constants below. This function will return false if the desired bonus is
//@ not a valid bonus type, or out of the range of bonuses that can be applied.
//@
//@ integer UnitGetBonus(unit <target unit>, integer <bonus type>)
//@
//@ Returns the bonus ammount of <bonus type> currently applied to <target unit>.
//@
//@ boolean UnitAddBonus(unit <target unit>, integer <bonus type>, integer <bonus ammount>)
//@
//@ This function will add <bonus ammount> to the bonus of type <bonus type> on the
//@ unit <target unit>. <bonus ammount> can be a negative value. This function will return
//@ false if the new bonus will be out of the range which bonus mod can apply.
//@
//@ nothing UnitClearBonus(unit <target unit>, integer <bonus type>)
//@
//@ This function will effectively set the bonus of type <bonus type> for the unit
//@ <target unit> to 0. It is advised you use this function over UnitSetBonus(..., ..., 0)
//@
//@---------------------------------------------------------------------------------------
//@ Variables:
//@
//@ BonusMod_MaxBonus
//@ The maximum bonus that Bonus Mod can apply
//@ BonusMod_MinBonus
//@ The minimum bonus that Bonus Mod can apply
//@---------------------------------------------------------------------------------------
//@ Increasing the Range of Bonuses:
//@
//@ By default, bonus mod uses 13 abilitys per bonus type. This gives each bonus type a
//@ range of -4096 to +4095. To increase this range, you will have to create one new
//@ ability for each ability, for each power of two you increase bonus mod by. You will
//@ also have to edit the negative bonus ability to apply a bonus of -2^(n+1), where n is
//@ the largest power of two you will be using for positive bonuses. You will need to edit
//@ the ABILITY_COUNT constant found below to reflect the new total number of abilitys
//@ each individual bonus will use. You will also have to add the abilitys to the function
//@ InitializeAbilitys. Note that the number in the array index indicates which power of
//@ 2 is held there. So, for instance, set BonusAbilitys[i + 15] would hold an ability
//@ which changes the relivent stat by 32768. (2^15 = 32768) The last ability in the array
//@ must apply a negative bonus.
//@
//@ Here is an example of the bonus BONUS_ARMOR using 15 abilitys instead of 12:
//@
//@ set i = BONUS_ARMOR * ABILITY_COUNT
//@ set BonusAbilitys[i + 0] = 'ZxA0' // +1
//@ set BonusAbilitys[i + 1] = 'ZxA1' // +2
//@ set BonusAbilitys[i + 2] = 'ZxA2' // +4
//@ set BonusAbilitys[i + 3] = 'ZxA3' // +8
//@ set BonusAbilitys[i + 4] = 'ZxA4' // +16
//@ set BonusAbilitys[i + 5] = 'ZxA5' // +32
//@ set BonusAbilitys[i + 6] = 'ZxA6' // +64
//@ set BonusAbilitys[i + 7] = 'ZxA7' // +128
//@ set BonusAbilitys[i + 8] = 'ZxA8' // +256
//@ set BonusAbilitys[i + 9] = 'ZxA9' // +512
//@ set BonusAbilitys[i + 10] = 'ZxAa' // +1024
//@ set BonusAbilitys[i + 11] = 'ZxAb' // +2048
//@ set BonusAbilitys[i + 12] = 'ZxAc' // +4096
//@ set BonusAbilitys[i + 13] = 'ZxAd' // +8192
//@ set BonusAbilitys[i + 14] = 'ZxAe' // +16384
//@ set BonusAbilitys[i + 15] = 'ZxAf' // -32768
//@
//@---------------------------------------------------------------------------------------
//@ Adding and Removing Bonus Types:
//@
//@ Removing a bonus type is simple. First, delete it from the list of constants found
//@ below. Make sure the constants are numberd 0, 1, 2, 3, etc. without any gaps. Change
//@ the BONUS_TYPES constant to reflect the new number of bonuses. You must then remove
//@ the lines of array initialization for the bonus you removed from the
//@ InitializeAbilitys function. You can then delete the abilitys for that bonus type, and
//@ you are then done removing a bonus type.
//@
//@ Adding a bonus type is done in much the same way. Add a constant for it to the list of
//@ constants below, ensuring they are numberd 0, 1, 2, 3 etc. withour any gaps. Change
//@ the BONUS_TYPES constant to reflect the new number of bonuses. You must then create
//@ all the needed abilitys for the new bonus type. Ensure the bonus they each apply is a
//@ power of 2, as with the already included bonuses. See the section Increasing the Range
//@ of Bonuses for more information. After all the abilitys are added, you must add the
//@ needed lines to the InitializeAbilitys function. The existing lines should be a clear
//@ enogh example.
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//////////////////////////////////////////////////////////////////////////////////////////
library BonusMod initializer Initialize

globals
//========================================================================================
// Bonus Type Constants
//========================================================================================

    constant integer BONUS_ARMOR = 0 // Armor Bonus
    constant integer BONUS_DAMAGE = 1 // Damage Bonus
    constant integer BONUS_SIGHT_RANGE = 2 // Sight Range Bonus
    constant integer BONUS_MANA_REGEN = 3 // Mana Regeneration Bonus (A % value)
    constant integer BONUS_LIFE_REGEN = 4 // Life Regeneration Bonus (An absolute value)
    constant integer BONUS_HERO_STR = 5 // Strength Bonus
    constant integer BONUS_HERO_AGI = 6 // Agility Bonus
    constant integer BONUS_HERO_INT = 7 // Intelligence Bonus
    constant integer BONUS_SPEED_MOVE = 8 // Movespeed Bonus (A % value)
    constant integer BONUS_SPEED_ATTACK = 9 // Attackspeed Bonus (A % value)

    // The number of bonus type constants above:
    constant integer BONUS_TYPES = 10

//========================================================================================
// Other Configuration
//========================================================================================

    // The number of abilitys used per bonus type:
    private constant integer ABILITY_COUNT = 13

    // Note: Setting the following to false will decrease loading time, but will cause a
    // small ammount of lag when a bonus is first applied. (Especially a negative bonus)
    // If set to true, all BonusMod abilitys will be preloaded:
    private constant boolean PRELOAD_ABILITYS = true

    // Only applies if PRELOAD_ABILITYS is set to true.
    // The unit type used to preload abilitys on:
    private constant integer PRELOAD_DUMMY_UNIT = 'hpea'
endglobals

//========================================================================================
// Ability Initialization
//----------------------------------------------------------------------------------------
// The following function is used to define the rawcodes for all the abilitys bonus mod
// uses. If you use the text macros included with BonusMod, and if you do not wish to add,
// remove, or change the range of bonuses, you will not have to edit the following.
//
// Note that if your map already has abilitys with rawcodes that begin with Zx followed by
// an upper-case letter, the ObjectMerger macros included with this library will not work
// and you will have to edit the lines below. However, you could use the find and replace
// feature in JASS NewGen's Trigger Editor Syntax Highlighter to replace all occurances of
// Zx both here and in the ObjectMerger macros to ease configuration.
//========================================================================================
private keyword BonusAbilitys
private function InitializeAbilitys takes nothing returns nothing
    local integer i

    // Bonus Mod - Armor abilitys
    set i = BONUS_ARMOR * ABILITY_COUNT
    set BonusAbilitys[i + 0] = 'ZxA0' // +1
    set BonusAbilitys[i + 1] = 'ZxA1' // +2
    set BonusAbilitys[i + 2] = 'ZxA2' // +4
    set BonusAbilitys[i + 3] = 'ZxA3' // +8
    set BonusAbilitys[i + 4] = 'ZxA4' // +16
    set BonusAbilitys[i + 5] = 'ZxA5' // +32
    set BonusAbilitys[i + 6] = 'ZxA6' // +64
    set BonusAbilitys[i + 7] = 'ZxA7' // +128
    set BonusAbilitys[i + 8] = 'ZxA8' // +256
    set BonusAbilitys[i + 9] = 'ZxA9' // +512
    set BonusAbilitys[i + 10] = 'ZxAa' // +1024
    set BonusAbilitys[i + 11] = 'ZxAb' // +2048
    set BonusAbilitys[i + 12] = 'ZxAc' // -4096

    // Bonus Mod - Damage abilitys
    set i = BONUS_DAMAGE * ABILITY_COUNT
    set BonusAbilitys[i + 0] = 'ZxB0' // +1
    set BonusAbilitys[i + 1] = 'ZxB1' // +2
    set BonusAbilitys[i + 2] = 'ZxB2' // +4
    set BonusAbilitys[i + 3] = 'ZxB3' // +8
    set BonusAbilitys[i + 4] = 'ZxB4' // +16
    set BonusAbilitys[i + 5] = 'ZxB5' // +32
    set BonusAbilitys[i + 6] = 'ZxB6' // +64
    set BonusAbilitys[i + 7] = 'ZxB7' // +128
    set BonusAbilitys[i + 8] = 'ZxB8' // +256
    set BonusAbilitys[i + 9] = 'ZxB9' // +512
    set BonusAbilitys[i + 10] = 'ZxBa' // +1024
    set BonusAbilitys[i + 11] = 'ZxBb' // +2048
    set BonusAbilitys[i + 12] = 'ZxBc' // -4096

    // Bonus Mod - Sight Range abilitys
    set i = BONUS_SIGHT_RANGE * ABILITY_COUNT
    set BonusAbilitys[i + 0] = 'ZxC0' // +1
    set BonusAbilitys[i + 1] = 'ZxC1' // +2
    set BonusAbilitys[i + 2] = 'ZxC2' // +4
    set BonusAbilitys[i + 3] = 'ZxC3' // +8
    set BonusAbilitys[i + 4] = 'ZxC4' // +16
    set BonusAbilitys[i + 5] = 'ZxC5' // +32
    set BonusAbilitys[i + 6] = 'ZxC6' // +64
    set BonusAbilitys[i + 7] = 'ZxC7' // +128
    set BonusAbilitys[i + 8] = 'ZxC8' // +256
    set BonusAbilitys[i + 9] = 'ZxC9' // +512
    set BonusAbilitys[i + 10] = 'ZxCa' // +1024
    set BonusAbilitys[i + 11] = 'ZxCb' // +2048
    set BonusAbilitys[i + 12] = 'ZxCc' // -4096

    // Bonus Mod - Mana Regen abilitys
    set i = BONUS_MANA_REGEN * ABILITY_COUNT
    set BonusAbilitys[i + 0] = 'ZxD0' // +1
    set BonusAbilitys[i + 1] = 'ZxD1' // +2
    set BonusAbilitys[i + 2] = 'ZxD2' // +4
    set BonusAbilitys[i + 3] = 'ZxD3' // +8
    set BonusAbilitys[i + 4] = 'ZxD4' // +16
    set BonusAbilitys[i + 5] = 'ZxD5' // +32
    set BonusAbilitys[i + 6] = 'ZxD6' // +64
    set BonusAbilitys[i + 7] = 'ZxD7' // +128
    set BonusAbilitys[i + 8] = 'ZxD8' // +256
    set BonusAbilitys[i + 9] = 'ZxD9' // +512
    set BonusAbilitys[i + 10] = 'ZxDa' // +1024
    set BonusAbilitys[i + 11] = 'ZxDb' // +2048
    set BonusAbilitys[i + 12] = 'ZxDc' // -4096

    // Bonus Mod - Life Regen abilitys
    set i = BONUS_LIFE_REGEN * ABILITY_COUNT
    set BonusAbilitys[i + 0] = 'ZxE0' // +1
    set BonusAbilitys[i + 1] = 'ZxE1' // +2
    set BonusAbilitys[i + 2] = 'ZxE2' // +4
    set BonusAbilitys[i + 3] = 'ZxE3' // +8
    set BonusAbilitys[i + 4] = 'ZxE4' // +16
    set BonusAbilitys[i + 5] = 'ZxE5' // +32
    set BonusAbilitys[i + 6] = 'ZxE6' // +64
    set BonusAbilitys[i + 7] = 'ZxE7' // +128
    set BonusAbilitys[i + 8] = 'ZxE8' // +256
    set BonusAbilitys[i + 9] = 'ZxE9' // +512
    set BonusAbilitys[i + 10] = 'ZxEa' // +1024
    set BonusAbilitys[i + 11] = 'ZxEb' // +2048
    set BonusAbilitys[i + 12] = 'ZxEc' // -4096

    // Bonus Mod - Hero STR abilitys
    set i = BONUS_HERO_STR * ABILITY_COUNT
    set BonusAbilitys[i + 0] = 'ZxF0' // +1
    set BonusAbilitys[i + 1] = 'ZxF1' // +2
    set BonusAbilitys[i + 2] = 'ZxF2' // +4
    set BonusAbilitys[i + 3] = 'ZxF3' // +8
    set BonusAbilitys[i + 4] = 'ZxF4' // +16
    set BonusAbilitys[i + 5] = 'ZxF5' // +32
    set BonusAbilitys[i + 6] = 'ZxF6' // +64
    set BonusAbilitys[i + 7] = 'ZxF7' // +128
    set BonusAbilitys[i + 8] = 'ZxF8' // +256
    set BonusAbilitys[i + 9] = 'ZxF9' // +512
    set BonusAbilitys[i + 10] = 'ZxFa' // +1024
    set BonusAbilitys[i + 11] = 'ZxFb' // +2048
    set BonusAbilitys[i + 12] = 'ZxFc' // -4096

    // Bonus Mod - Hero AGI abilitys
    set i = BONUS_HERO_AGI * ABILITY_COUNT
    set BonusAbilitys[i + 0] = 'ZxG0' // +1
    set BonusAbilitys[i + 1] = 'ZxG1' // +2
    set BonusAbilitys[i + 2] = 'ZxG2' // +4
    set BonusAbilitys[i + 3] = 'ZxG3' // +8
    set BonusAbilitys[i + 4] = 'ZxG4' // +16
    set BonusAbilitys[i + 5] = 'ZxG5' // +32
    set BonusAbilitys[i + 6] = 'ZxG6' // +64
    set BonusAbilitys[i + 7] = 'ZxG7' // +128
    set BonusAbilitys[i + 8] = 'ZxG8' // +256
    set BonusAbilitys[i + 9] = 'ZxG9' // +512
    set BonusAbilitys[i + 10] = 'ZxGa' // +1024
    set BonusAbilitys[i + 11] = 'ZxGb' // +2048
    set BonusAbilitys[i + 12] = 'ZxGc' // -4096

    // Bonus Mod - Hero INT abilitys
    set i = BONUS_HERO_INT * ABILITY_COUNT
    set BonusAbilitys[i + 0] = 'ZxH0' // +1
    set BonusAbilitys[i + 1] = 'ZxH1' // +2
    set BonusAbilitys[i + 2] = 'ZxH2' // +4
    set BonusAbilitys[i + 3] = 'ZxH3' // +8
    set BonusAbilitys[i + 4] = 'ZxH4' // +16
    set BonusAbilitys[i + 5] = 'ZxH5' // +32
    set BonusAbilitys[i + 6] = 'ZxH6' // +64
    set BonusAbilitys[i + 7] = 'ZxH7' // +128
    set BonusAbilitys[i + 8] = 'ZxH8' // +256
    set BonusAbilitys[i + 9] = 'ZxH9' // +512
    set BonusAbilitys[i + 10] = 'ZxHa' // +1024
    set BonusAbilitys[i + 11] = 'ZxHb' // +2048
    set BonusAbilitys[i + 12] = 'ZxHc' // -4096
    
    // Bonus Mod - Move Speed Abilities
    set i = BONUS_SPEED_MOVE * ABILITY_COUNT
    set BonusAbilitys[i + 0] = 'ZxI0' // +1
    set BonusAbilitys[i + 1] = 'ZxI1' // +2
    set BonusAbilitys[i + 2] = 'ZxI2' // +4
    set BonusAbilitys[i + 3] = 'ZxI3' // +8
    set BonusAbilitys[i + 4] = 'ZxI4' // +16
    set BonusAbilitys[i + 5] = 'ZxI5' // +32
    set BonusAbilitys[i + 6] = 'ZxI6' // +64
    set BonusAbilitys[i + 7] = 'ZxI7' // +128
    set BonusAbilitys[i + 8] = 'ZxI8' // +256
    set BonusAbilitys[i + 9] = 'ZxI9' // +512
    set BonusAbilitys[i + 10] = 'ZxIa' // +1024
    set BonusAbilitys[i + 11] = 'ZxIb' // +2048
    set BonusAbilitys[i + 12] = 'ZxIc' // -4096
    
    // Bonus Mod - Attack Speed Abilities
    set i = BONUS_SPEED_ATTACK * ABILITY_COUNT
    set BonusAbilitys[i + 0] = 'ZxJ0' // +1
    set BonusAbilitys[i + 1] = 'ZxJ1' // +2
    set BonusAbilitys[i + 2] = 'ZxJ2' // +4
    set BonusAbilitys[i + 3] = 'ZxJ3' // +8
    set BonusAbilitys[i + 4] = 'ZxJ4' // +16
    set BonusAbilitys[i + 5] = 'ZxJ5' // +32
    set BonusAbilitys[i + 6] = 'ZxJ6' // +64
    set BonusAbilitys[i + 7] = 'ZxJ7' // +128
    set BonusAbilitys[i + 8] = 'ZxJ8' // +256
    set BonusAbilitys[i + 9] = 'ZxJ9' // +512
    set BonusAbilitys[i + 10] = 'ZxJa' // +1024
    set BonusAbilitys[i + 11] = 'ZxJb' // +2048
    set BonusAbilitys[i + 12] = 'ZxJc' // -4096
endfunction

//========================================================================================
// System Code
//----------------------------------------------------------------------------------------
// Do not edit below this line unless you wish to change the way the system works.
//========================================================================================

globals
    // Contains all abilitys in a two-dimensional structure:
    private integer array BonusAbilitys

    // Precomputed powers of two to avoid speed and rounding issues with Pow():
    private integer array PowersOf2

    // Range constants (Read only please):
    public integer MaxBonus
    public integer MinBonus
endglobals

function UnitClearBonus takes unit u, integer bonusType returns nothing
    local integer i = 0

    loop
        call UnitRemoveAbility(u, BonusAbilitys[bonusType * ABILITY_COUNT + i])

        set i = i + 1
        exitwhen i == ABILITY_COUNT - 2
    endloop
endfunction

function UnitSetBonus takes unit u, integer bonusType, integer ammount returns boolean
    local integer i = ABILITY_COUNT - 2

    if ammount < MinBonus or ammount > MaxBonus then
        debug call BJDebugMsg("BonusSystem Error: Bonus too high or low (" + I2S(ammount) + ")")
        return false
    elseif bonusType < 0 or bonusType >= BONUS_TYPES then
        debug call BJDebugMsg("BonusSystem Error: Invalid bonus type (" + I2S(bonusType) + ")")
        return false
    endif

    if ammount < 0 then
        set ammount = MaxBonus + ammount + 1
        call UnitAddAbility(u, BonusAbilitys[bonusType * ABILITY_COUNT + ABILITY_COUNT - 1])
        call UnitMakeAbilityPermanent(u, true, BonusAbilitys[bonusType * ABILITY_COUNT + ABILITY_COUNT - 1])
    else
        call UnitRemoveAbility(u, BonusAbilitys[bonusType * ABILITY_COUNT + ABILITY_COUNT - 1])
    endif

    loop
        if ammount >= PowersOf2[i] then
            call UnitAddAbility(u, BonusAbilitys[bonusType * ABILITY_COUNT + i])
            call UnitMakeAbilityPermanent(u, true, BonusAbilitys[bonusType * ABILITY_COUNT + i])
set ammount = ammount - PowersOf2[i]
        else
            call UnitRemoveAbility(u, BonusAbilitys[bonusType * ABILITY_COUNT + i])
        endif

        set i = i - 1
        exitwhen i < 0
    endloop

    return true
endfunction

function UnitGetBonus takes unit u, integer bonusType returns integer
    local integer i = 0
    local integer ammount = 0

    if GetUnitAbilityLevel(u, BonusAbilitys[bonusType * ABILITY_COUNT + ABILITY_COUNT - 1]) > 0 then
        set ammount = MinBonus
    endif

    loop
        if GetUnitAbilityLevel(u, BonusAbilitys[bonusType * ABILITY_COUNT + i]) > 0 then
            set ammount = ammount + PowersOf2[i]
        endif

        set i = i + 1
        exitwhen i == ABILITY_COUNT - 2
    endloop

    return ammount
endfunction

function UnitAddBonus takes unit u, integer bonusType, integer ammount returns boolean
    return UnitSetBonus(u, bonusType, UnitGetBonus(u, bonusType) + ammount)
endfunction

private function Initialize takes nothing returns nothing
    local integer i = 1
    local unit u

    set PowersOf2[0] = 1
    loop
        set PowersOf2[i] = PowersOf2[i - 1] * 2
        set i = i + 1
        exitwhen i == ABILITY_COUNT
    endloop

    set MaxBonus = PowersOf2[ABILITY_COUNT - 1] - 1
    set MinBonus = -PowersOf2[ABILITY_COUNT - 1]

    call InitializeAbilitys()

    if PRELOAD_ABILITYS then
        set u = CreateUnit(Player(15), PRELOAD_DUMMY_UNIT, 0, 0, 0)
        set i = 0
        loop
            exitwhen i == BONUS_TYPES * ABILITY_COUNT
            call UnitAddAbility(u, BonusAbilitys[i])
            set i = i + 1
        endloop
        call RemoveUnit(u)
    endif
endfunction
endlibrary



JASS:
// About these macros:
//
// The first paramiter is the rawcode for the ability. The convention used here by default is:
// Zx followed by an uppercase letter, unique to the bonus, followed by a 0-9-a-z representing
// the base of two the ability applys.
//
// The second paramiter is the display value of the ability. This is so that they all line up
// neatly in the object editor.
//
// The third paramiter is the actual value the bonus ability applys.
//
// Note that you should copy this in to its own trigger, save once, close the map and re-open
// it in the World Editor, then disable the trigger you copied this in to. If you do not
// disable the trigger, saving will take an insane ammount of time every time you save. If you
// make any changes below, you can simply enable the trigger again, save again, then disable
// the trigger again.

// BonusMod - Armor
//============================================================================================
//! textmacro ArmorAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AId1 $RAWCODE$ Idef 1 $VALUE$ anam "BonusMod - Armor ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNHumanArmorUpOne.blp
//! endtextmacro

//! runtextmacro ArmorAbility("ZxA0", "+0001", "1")
//! runtextmacro ArmorAbility("ZxA1", "+0002", "2")
//! runtextmacro ArmorAbility("ZxA2", "+0004", "4")
//! runtextmacro ArmorAbility("ZxA3", "+0008", "8")
//! runtextmacro ArmorAbility("ZxA4", "+0016", "16")
//! runtextmacro ArmorAbility("ZxA5", "+0032", "32")
//! runtextmacro ArmorAbility("ZxA6", "+0064", "64")
//! runtextmacro ArmorAbility("ZxA7", "+0128", "128")
//! runtextmacro ArmorAbility("ZxA8", "+0256", "256")
//! runtextmacro ArmorAbility("ZxA9", "+0512", "512")
//! runtextmacro ArmorAbility("ZxAa", "+1024", "1024")
//! runtextmacro ArmorAbility("ZxAb", "+2048", "2048")
//! runtextmacro ArmorAbility("ZxAc", "-4096", "-4096")

// BonusMod - Damage
//============================================================================================
//! textmacro DamageAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AItg $RAWCODE$ Iatt 1 $VALUE$ anam "BonusMod - Damage ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNSteelMelee.blp
//! endtextmacro

//! runtextmacro DamageAbility("ZxB0", "+0001", "1")
//! runtextmacro DamageAbility("ZxB1", "+0002", "2")
//! runtextmacro DamageAbility("ZxB2", "+0004", "4")
//! runtextmacro DamageAbility("ZxB3", "+0008", "8")
//! runtextmacro DamageAbility("ZxB4", "+0016", "16")
//! runtextmacro DamageAbility("ZxB5", "+0032", "32")
//! runtextmacro DamageAbility("ZxB6", "+0064", "64")
//! runtextmacro DamageAbility("ZxB7", "+0128", "128")
//! runtextmacro DamageAbility("ZxB8", "+0256", "256")
//! runtextmacro DamageAbility("ZxB9", "+0512", "512")
//! runtextmacro DamageAbility("ZxBa", "+1024", "1024")
//! runtextmacro DamageAbility("ZxBb", "+2048", "2048")
//! runtextmacro DamageAbility("ZxBc", "-4096", "-4096")

// BonusMod - Sight Range
//============================================================================================
//! textmacro SightRangeAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIsi $RAWCODE$ Isib 1 $VALUE$ anam "BonusMod - Sight Range ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNTelescope.blp
//! endtextmacro

//! runtextmacro SightRangeAbility("ZxC0", "+0001", "1")
//! runtextmacro SightRangeAbility("ZxC1", "+0002", "2")
//! runtextmacro SightRangeAbility("ZxC2", "+0004", "4")
//! runtextmacro SightRangeAbility("ZxC3", "+0008", "8")
//! runtextmacro SightRangeAbility("ZxC4", "+0016", "16")
//! runtextmacro SightRangeAbility("ZxC5", "+0032", "32")
//! runtextmacro SightRangeAbility("ZxC6", "+0064", "64")
//! runtextmacro SightRangeAbility("ZxC7", "+0128", "128")
//! runtextmacro SightRangeAbility("ZxC8", "+0256", "256")
//! runtextmacro SightRangeAbility("ZxC9", "+0512", "512")
//! runtextmacro SightRangeAbility("ZxCa", "+1024", "1024")
//! runtextmacro SightRangeAbility("ZxCb", "+2048", "2048")
//! runtextmacro SightRangeAbility("ZxCc", "-4096", "-4096")

// BonusMod - Mana Regeneration
//============================================================================================
//! textmacro ManaRegenAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIrm $RAWCODE$ Imrp 1 $VALUE$ anam "BonusMod - Mana Regen ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNSobiMask.blp
//! endtextmacro

//! runtextmacro ManaRegenAbility("ZxD0", "+0001", "0.01")
//! runtextmacro ManaRegenAbility("ZxD1", "+0002", "0.02")
//! runtextmacro ManaRegenAbility("ZxD2", "+0004", "0.04")
//! runtextmacro ManaRegenAbility("ZxD3", "+0008", "0.08")
//! runtextmacro ManaRegenAbility("ZxD4", "+0016", "0.16")
//! runtextmacro ManaRegenAbility("ZxD5", "+0032", "0.32")
//! runtextmacro ManaRegenAbility("ZxD6", "+0064", "0.64")
//! runtextmacro ManaRegenAbility("ZxD7", "+0128", "1.28")
//! runtextmacro ManaRegenAbility("ZxD8", "+0256", "2.56")
//! runtextmacro ManaRegenAbility("ZxD9", "+0512", "5.12")
//! runtextmacro ManaRegenAbility("ZxDa", "+1024", "10.24")
//! runtextmacro ManaRegenAbility("ZxDb", "+2048", "20.48")
//! runtextmacro ManaRegenAbility("ZxDc", "-4096", "-40.96")

// BonusMod - Life Regenration
//============================================================================================
//! textmacro LifeRegenAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a Arel $RAWCODE$ Ihpr 1 $VALUE$ anam "BonusMod - Life Regen ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNRingSkull.blp
//! endtextmacro

//! runtextmacro LifeRegenAbility("ZxE0", "+0001", "1")
//! runtextmacro LifeRegenAbility("ZxE1", "+0002", "2")
//! runtextmacro LifeRegenAbility("ZxE2", "+0004", "4")
//! runtextmacro LifeRegenAbility("ZxE3", "+0008", "8")
//! runtextmacro LifeRegenAbility("ZxE4", "+0016", "16")
//! runtextmacro LifeRegenAbility("ZxE5", "+0032", "32")
//! runtextmacro LifeRegenAbility("ZxE6", "+0064", "64")
//! runtextmacro LifeRegenAbility("ZxE7", "+0128", "128")
//! runtextmacro LifeRegenAbility("ZxE8", "+0256", "256")
//! runtextmacro LifeRegenAbility("ZxE9", "+0512", "512")
//! runtextmacro LifeRegenAbility("ZxEa", "+1024", "1024")
//! runtextmacro LifeRegenAbility("ZxEb", "+2048", "2048")
//! runtextmacro LifeRegenAbility("ZxEc", "-4096", "-4096")

// BonusMod - Strength
//============================================================================================
//! textmacro HeroStrAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIa1 $RAWCODE$ Iagi 1 0 Iint 1 0 Istr 1 $VALUE$ anam "BonusMod - Hero STR ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNGoldRing.blp
//! endtextmacro

//! runtextmacro HeroStrAbility("ZxF0", "+0001", "1")
//! runtextmacro HeroStrAbility("ZxF1", "+0002", "2")
//! runtextmacro HeroStrAbility("ZxF2", "+0004", "4")
//! runtextmacro HeroStrAbility("ZxF3", "+0008", "8")
//! runtextmacro HeroStrAbility("ZxF4", "+0016", "16")
//! runtextmacro HeroStrAbility("ZxF5", "+0032", "32")
//! runtextmacro HeroStrAbility("ZxF6", "+0064", "64")
//! runtextmacro HeroStrAbility("ZxF7", "+0128", "128")
//! runtextmacro HeroStrAbility("ZxF8", "+0256", "256")
//! runtextmacro HeroStrAbility("ZxF9", "+0512", "512")
//! runtextmacro HeroStrAbility("ZxFa", "+1024", "1024")
//! runtextmacro HeroStrAbility("ZxFb", "+2048", "2048")
//! runtextmacro HeroStrAbility("ZxFc", "-4096", "-4096")

// BonusMod - Agility
//============================================================================================
//! textmacro HeroAgiAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIa1 $RAWCODE$ Iagi 1 $VALUE$ Iint 1 0 Istr 1 0 anam "BonusMod - Hero AGI ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNGoldRing.blp
//! endtextmacro

//! runtextmacro HeroAgiAbility("ZxG0", "+0001", "1")
//! runtextmacro HeroAgiAbility("ZxG1", "+0002", "2")
//! runtextmacro HeroAgiAbility("ZxG2", "+0004", "4")
//! runtextmacro HeroAgiAbility("ZxG3", "+0008", "8")
//! runtextmacro HeroAgiAbility("ZxG4", "+0016", "16")
//! runtextmacro HeroAgiAbility("ZxG5", "+0032", "32")
//! runtextmacro HeroAgiAbility("ZxG6", "+0064", "64")
//! runtextmacro HeroAgiAbility("ZxG7", "+0128", "128")
//! runtextmacro HeroAgiAbility("ZxG8", "+0256", "256")
//! runtextmacro HeroAgiAbility("ZxG9", "+0512", "512")
//! runtextmacro HeroAgiAbility("ZxGa", "+1024", "1024")
//! runtextmacro HeroAgiAbility("ZxGb", "+2048", "2048")
//! runtextmacro HeroAgiAbility("ZxGc", "-4096", "-4096")

// BonusMod - Intelligence
//============================================================================================
//! textmacro HeroIntAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIa1 $RAWCODE$ Iagi 1 0 Iint 1 $VALUE$ Istr 1 0 anam "BonusMod - Hero INT ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNGoldRing.blp
//! endtextmacro

//! runtextmacro HeroIntAbility("ZxH0", "+0001", "1")
//! runtextmacro HeroIntAbility("ZxH1", "+0002", "2")
//! runtextmacro HeroIntAbility("ZxH2", "+0004", "4")
//! runtextmacro HeroIntAbility("ZxH3", "+0008", "8")
//! runtextmacro HeroIntAbility("ZxH4", "+0016", "16")
//! runtextmacro HeroIntAbility("ZxH5", "+0032", "32")
//! runtextmacro HeroIntAbility("ZxH6", "+0064", "64")
//! runtextmacro HeroIntAbility("ZxH7", "+0128", "128")
//! runtextmacro HeroIntAbility("ZxH8", "+0256", "256")
//! runtextmacro HeroIntAbility("ZxH9", "+0512", "512")
//! runtextmacro HeroIntAbility("ZxHa", "+1024", "1024")
//! runtextmacro HeroIntAbility("ZxHb", "+2048", "2048")
//! runtextmacro HeroIntAbility("ZxHc", "-4096", "-4096")

// BonusMod - Move Speed
//============================================================================================
//! textmacro HeroMSAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIms $RAWCODE$ Imvb 1 $VALUE$ anam "BonusMod - Move Speed ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNBootsOfSpeed.blp
//! endtextmacro

//! runtextmacro HeroMSAbility("ZxI0", "+0001", "0001")
//! runtextmacro HeroMSAbility("ZxI1", "+0002", "0002")
//! runtextmacro HeroMSAbility("ZxI2", "+0004", "0004")
//! runtextmacro HeroMSAbility("ZxI3", "+0008", "0008")
//! runtextmacro HeroMSAbility("ZxI4", "+0016", "0016")
//! runtextmacro HeroMSAbility("ZxI5", "+0032", "0032")
//! runtextmacro HeroMSAbility("ZxI6", "+0064", "0064")
//! runtextmacro HeroMSAbility("ZxI7", "+0128", "0128")
//! runtextmacro HeroMSAbility("ZxI8", "+0256", "0256")
//! runtextmacro HeroMSAbility("ZxI9", "+0512", "0512")
//! runtextmacro HeroMSAbility("ZxIa", "+1024", "1024")
//! runtextmacro HeroMSAbility("ZxIb", "+2048", "2048")
//! runtextmacro HeroMSAbility("ZxIc", "-4096", "-4096")

// BonusMod - Attack Speed
//============================================================================================
//! textmacro HeroASAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIsx $RAWCODE$ Isx1 1 $VALUE$ anam "BonusMod - Attack Speed ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNGlove.blp
//! endtextmacro

//! runtextmacro HeroASAbility("ZxJ0", "+00.01", "0.01")
//! runtextmacro HeroASAbility("ZxJ1", "+00.02", "0.02")
//! runtextmacro HeroASAbility("ZxJ2", "+00.04", "0.04")
//! runtextmacro HeroASAbility("ZxJ3", "+00.08", "0.08")
//! runtextmacro HeroASAbility("ZxJ4", "+00.16", "0.16")
//! runtextmacro HeroASAbility("ZxJ5", "+00.32", "0.32")
//! runtextmacro HeroASAbility("ZxJ6", "+00.64", "0.64")
//! runtextmacro HeroASAbility("ZxJ7", "+01.28", "1.28")
//! runtextmacro HeroASAbility("ZxJ8", "+02.56", "2.56")
//! runtextmacro HeroASAbility("ZxJ9", "+05.12", "5.12")
//! runtextmacro HeroASAbility("ZxJa", "+10.24", "10.24")
//! runtextmacro HeroASAbility("ZxJb", "+20.48", "20.48")
//! runtextmacro HeroASAbility("ZxJc", "-40.96", "-40.96")

// Don't let a //! external command be the last line in a trigger!
 
Last edited:
The reason movespeed doesn't work isn't because of the function - it's because of the game mechanics. All units have a maximum and minimum move speeds, and nothing can make it go over these values.

Who cares? we are actually talking about STACKING, and not about max unit speed.

I wonder why movement speed doesn't stuck like armor bonusses etc.
 
Level 7
Joined
Aug 13, 2007
Messages
309
My point is, it's not that it doesn't stack, it's that you don't see it stacking because there is a limit to how high the movespeed can actually go.

You can change the the maximum and minimum movespeed to whatever you want. For example, import a .txt file to your map called war3mapMisc.txt that has the following written in it.

Code:
[Misc]
MinUnitSpeed=0.0
MaxUnitSpeed=999999999999999.0

make sure the path is war3mapMisc.txt and not war3mapImported/war3mapMisc.txt before you save your map. Btw, you can also change the chat font here and if you attach/remove effects you could do "EffectDeathTime=0.0" so they disappear right away (Normally they take 5.0 seconds to go away) among other things you can modify.
 
Level 6
Joined
Oct 10, 2009
Messages
1,425
can somebody explain to me how the macros work? i imported them into a converted trigger just like it said, i saved and closed, then reopened the map and no new abilities... sorry if this is a dumb question but can somebody show me what the in-game trigger looks like?
 
If you're not running the Lua scripts, it won't work.

edit
Not Lua, I meant ObjectMerger.

Just copy this into a new trigger and save the map:

JASS:
// About these macros:
//
// The first paramiter is the rawcode for the ability. The convention used here by default is:
// Zx followed by an uppercase letter, unique to the bonus, followed by a 0-9-a-z representing
// the base of two the ability applys.
//
// The second paramiter is the display value of the ability. This is so that they all line up
// neatly in the object editor.
//
// The third paramiter is the actual value the bonus ability applys.
//
// Note that you should copy this in to its own trigger, save once, close the map and re-open
// it in the World Editor, then disable the trigger you copied this in to. If you do not
// disable the trigger, saving will take an insane ammount of time every time you save. If you
// make any changes below, you can simply enable the trigger again, save again, then disable
// the trigger again.

// BonusMod - Armor
//============================================================================================
//! textmacro ArmorAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AId1 $RAWCODE$ Idef 1 $VALUE$ anam "BonusMod - Armor ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNHumanArmorUpOne.blp
//! endtextmacro

//! runtextmacro ArmorAbility("ZxA0", "+0001", "1")
//! runtextmacro ArmorAbility("ZxA1", "+0002", "2")
//! runtextmacro ArmorAbility("ZxA2", "+0004", "4")
//! runtextmacro ArmorAbility("ZxA3", "+0008", "8")
//! runtextmacro ArmorAbility("ZxA4", "+0016", "16")
//! runtextmacro ArmorAbility("ZxA5", "+0032", "32")
//! runtextmacro ArmorAbility("ZxA6", "+0064", "64")
//! runtextmacro ArmorAbility("ZxA7", "+0128", "128")
//! runtextmacro ArmorAbility("ZxA8", "+0256", "256")
//! runtextmacro ArmorAbility("ZxA9", "+0512", "512")
//! runtextmacro ArmorAbility("ZxAa", "+1024", "1024")
//! runtextmacro ArmorAbility("ZxAb", "+2048", "2048")
//! runtextmacro ArmorAbility("ZxAc", "-4096", "-4096")

// BonusMod - Damage
//============================================================================================
//! textmacro DamageAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AItg $RAWCODE$ Iatt 1 $VALUE$ anam "BonusMod - Damage ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNSteelMelee.blp
//! endtextmacro

//! runtextmacro DamageAbility("ZxB0", "+0001", "1")
//! runtextmacro DamageAbility("ZxB1", "+0002", "2")
//! runtextmacro DamageAbility("ZxB2", "+0004", "4")
//! runtextmacro DamageAbility("ZxB3", "+0008", "8")
//! runtextmacro DamageAbility("ZxB4", "+0016", "16")
//! runtextmacro DamageAbility("ZxB5", "+0032", "32")
//! runtextmacro DamageAbility("ZxB6", "+0064", "64")
//! runtextmacro DamageAbility("ZxB7", "+0128", "128")
//! runtextmacro DamageAbility("ZxB8", "+0256", "256")
//! runtextmacro DamageAbility("ZxB9", "+0512", "512")
//! runtextmacro DamageAbility("ZxBa", "+1024", "1024")
//! runtextmacro DamageAbility("ZxBb", "+2048", "2048")
//! runtextmacro DamageAbility("ZxBc", "-4096", "-4096")

// BonusMod - Sight Range
//============================================================================================
//! textmacro SightRangeAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIsi $RAWCODE$ Isib 1 $VALUE$ anam "BonusMod - Sight Range ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNTelescope.blp
//! endtextmacro

//! runtextmacro SightRangeAbility("ZxC0", "+0001", "1")
//! runtextmacro SightRangeAbility("ZxC1", "+0002", "2")
//! runtextmacro SightRangeAbility("ZxC2", "+0004", "4")
//! runtextmacro SightRangeAbility("ZxC3", "+0008", "8")
//! runtextmacro SightRangeAbility("ZxC4", "+0016", "16")
//! runtextmacro SightRangeAbility("ZxC5", "+0032", "32")
//! runtextmacro SightRangeAbility("ZxC6", "+0064", "64")
//! runtextmacro SightRangeAbility("ZxC7", "+0128", "128")
//! runtextmacro SightRangeAbility("ZxC8", "+0256", "256")
//! runtextmacro SightRangeAbility("ZxC9", "+0512", "512")
//! runtextmacro SightRangeAbility("ZxCa", "+1024", "1024")
//! runtextmacro SightRangeAbility("ZxCb", "+2048", "2048")
//! runtextmacro SightRangeAbility("ZxCc", "-4096", "-4096")

// BonusMod - Mana Regeneration
//============================================================================================
//! textmacro ManaRegenAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIrm $RAWCODE$ Imrp 1 $VALUE$ anam "BonusMod - Mana Regen ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNSobiMask.blp
//! endtextmacro

//! runtextmacro ManaRegenAbility("ZxD0", "+0001", "0.01")
//! runtextmacro ManaRegenAbility("ZxD1", "+0002", "0.02")
//! runtextmacro ManaRegenAbility("ZxD2", "+0004", "0.04")
//! runtextmacro ManaRegenAbility("ZxD3", "+0008", "0.08")
//! runtextmacro ManaRegenAbility("ZxD4", "+0016", "0.16")
//! runtextmacro ManaRegenAbility("ZxD5", "+0032", "0.32")
//! runtextmacro ManaRegenAbility("ZxD6", "+0064", "0.64")
//! runtextmacro ManaRegenAbility("ZxD7", "+0128", "1.28")
//! runtextmacro ManaRegenAbility("ZxD8", "+0256", "2.56")
//! runtextmacro ManaRegenAbility("ZxD9", "+0512", "5.12")
//! runtextmacro ManaRegenAbility("ZxDa", "+1024", "10.24")
//! runtextmacro ManaRegenAbility("ZxDb", "+2048", "20.48")
//! runtextmacro ManaRegenAbility("ZxDc", "-4096", "-40.96")

// BonusMod - Life Regenration
//============================================================================================
//! textmacro LifeRegenAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a Arel $RAWCODE$ Ihpr 1 $VALUE$ anam "BonusMod - Life Regen ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNRingSkull.blp
//! endtextmacro

//! runtextmacro LifeRegenAbility("ZxE0", "+0001", "1")
//! runtextmacro LifeRegenAbility("ZxE1", "+0002", "2")
//! runtextmacro LifeRegenAbility("ZxE2", "+0004", "4")
//! runtextmacro LifeRegenAbility("ZxE3", "+0008", "8")
//! runtextmacro LifeRegenAbility("ZxE4", "+0016", "16")
//! runtextmacro LifeRegenAbility("ZxE5", "+0032", "32")
//! runtextmacro LifeRegenAbility("ZxE6", "+0064", "64")
//! runtextmacro LifeRegenAbility("ZxE7", "+0128", "128")
//! runtextmacro LifeRegenAbility("ZxE8", "+0256", "256")
//! runtextmacro LifeRegenAbility("ZxE9", "+0512", "512")
//! runtextmacro LifeRegenAbility("ZxEa", "+1024", "1024")
//! runtextmacro LifeRegenAbility("ZxEb", "+2048", "2048")
//! runtextmacro LifeRegenAbility("ZxEc", "-4096", "-4096")

// BonusMod - Strength
//============================================================================================
//! textmacro HeroStrAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIa1 $RAWCODE$ Iagi 1 0 Iint 1 0 Istr 1 $VALUE$ anam "BonusMod - Hero STR ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNGoldRing.blp
//! endtextmacro

//! runtextmacro HeroStrAbility("ZxF0", "+0001", "1")
//! runtextmacro HeroStrAbility("ZxF1", "+0002", "2")
//! runtextmacro HeroStrAbility("ZxF2", "+0004", "4")
//! runtextmacro HeroStrAbility("ZxF3", "+0008", "8")
//! runtextmacro HeroStrAbility("ZxF4", "+0016", "16")
//! runtextmacro HeroStrAbility("ZxF5", "+0032", "32")
//! runtextmacro HeroStrAbility("ZxF6", "+0064", "64")
//! runtextmacro HeroStrAbility("ZxF7", "+0128", "128")
//! runtextmacro HeroStrAbility("ZxF8", "+0256", "256")
//! runtextmacro HeroStrAbility("ZxF9", "+0512", "512")
//! runtextmacro HeroStrAbility("ZxFa", "+1024", "1024")
//! runtextmacro HeroStrAbility("ZxFb", "+2048", "2048")
//! runtextmacro HeroStrAbility("ZxFc", "-4096", "-4096")

// BonusMod - Agility
//============================================================================================
//! textmacro HeroAgiAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIa1 $RAWCODE$ Iagi 1 $VALUE$ Iint 1 0 Istr 1 0 anam "BonusMod - Hero AGI ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNGoldRing.blp
//! endtextmacro

//! runtextmacro HeroAgiAbility("ZxG0", "+0001", "1")
//! runtextmacro HeroAgiAbility("ZxG1", "+0002", "2")
//! runtextmacro HeroAgiAbility("ZxG2", "+0004", "4")
//! runtextmacro HeroAgiAbility("ZxG3", "+0008", "8")
//! runtextmacro HeroAgiAbility("ZxG4", "+0016", "16")
//! runtextmacro HeroAgiAbility("ZxG5", "+0032", "32")
//! runtextmacro HeroAgiAbility("ZxG6", "+0064", "64")
//! runtextmacro HeroAgiAbility("ZxG7", "+0128", "128")
//! runtextmacro HeroAgiAbility("ZxG8", "+0256", "256")
//! runtextmacro HeroAgiAbility("ZxG9", "+0512", "512")
//! runtextmacro HeroAgiAbility("ZxGa", "+1024", "1024")
//! runtextmacro HeroAgiAbility("ZxGb", "+2048", "2048")
//! runtextmacro HeroAgiAbility("ZxGc", "-4096", "-4096")

// BonusMod - Intelligence
//============================================================================================
//! textmacro HeroIntAbility takes RAWCODE, DISPLAYVALUE, VALUE
//! external ObjectMerger w3a AIa1 $RAWCODE$ Iagi 1 0 Iint 1 $VALUE$ Istr 1 0 anam "BonusMod - Hero INT ($DISPLAYVALUE$)" aite 0 ansf "" aart ReplaceableTextures\CommandButtons\BTNGoldRing.blp
//! endtextmacro

//! runtextmacro HeroIntAbility("ZxH0", "+0001", "1")
//! runtextmacro HeroIntAbility("ZxH1", "+0002", "2")
//! runtextmacro HeroIntAbility("ZxH2", "+0004", "4")
//! runtextmacro HeroIntAbility("ZxH3", "+0008", "8")
//! runtextmacro HeroIntAbility("ZxH4", "+0016", "16")
//! runtextmacro HeroIntAbility("ZxH5", "+0032", "32")
//! runtextmacro HeroIntAbility("ZxH6", "+0064", "64")
//! runtextmacro HeroIntAbility("ZxH7", "+0128", "128")
//! runtextmacro HeroIntAbility("ZxH8", "+0256", "256")
//! runtextmacro HeroIntAbility("ZxH9", "+0512", "512")
//! runtextmacro HeroIntAbility("ZxHa", "+1024", "1024")
//! runtextmacro HeroIntAbility("ZxHb", "+2048", "2048")
//! runtextmacro HeroIntAbility("ZxHc", "-4096", "-4096")

// Don't let a //! external command be the last line in a trigger!

The abilities will be created.
Then delete this code and save again.

For SetUnitMaxState, use this:

JASS:
// The Mana ability:
//! external ObjectMerger w3a AImz Zx00 alev 19 aite 0 Iman 1 0 Iman 2 1 Iman 3 2 Iman 4 4 Iman 5 8 Iman 6 16 Iman 7 32 Iman 8 64 Iman 9 128 Iman 10 256 Iman 11 -1 Iman 12 -2 Iman 13 -4 Iman 14 -8 Iman 15 -16 Iman 16 -32 Iman 17 -64 Iman 18 -128 Iman 19 -256 anam "SetUnitMaxState - Mana" ansf "" aart ReplaceableTextures\CommandButtons\BTNManaStone.blp

// The Life ability:
//! external ObjectMerger w3a AIlf Zx01 alev 19 aite 0 Ilif 1 0 Ilif 2 1 Ilif 3 2 Ilif 4 4 Ilif 5 8 Ilif 6 16 Ilif 7 32 Ilif 8 64 Ilif 9 128 Ilif 10 256 Ilif 11 -1 Ilif 12 -2 Ilif 13 -4 Ilif 14 -8 Ilif 15 -16 Ilif 16 -32 Ilif 17 -64 Ilif 18 -128 Ilif 19 -256 anam "SetUnitMaxState - Life" ansf "" aart ReplaceableTextures\CommandButtons\BTNHealthStone.blp

// Don't let a //! external command be the last line in a trigger!
 

Deleted member 219079

D

Deleted member 219079

So there is not bonus stats library approved atm?
 

Deleted member 219079

D

Deleted member 219079

I have one on my hard drive. What should I change to make it approvable?
JASS:
library BonusStats requires AIDS // http://www.thehelper.net/threads/advanced-indexing-data-storage.116539/
    //////////////////////////////////////////////////////////////////
    //                                                              //
    // BonusStats v1.0.0                                            //
    // by jondrean                                                  //
    //                                                              //
    // d:26.03.16                                                   //
    //                                                              //
    // Armor/damage/hero attribute bonus up/down to ±(2^31-1)       //
    //                                                              //
    // Implementation:                                              //
    //  1. Save map once, having 2 ^ (textmacro input) greater      //
    //     than your desired max bonus value                        //
    //  2. Comment out second textmacro call below                  //
    //                                                              //
    //! runtextmacro BONUSSTATS_OBJECTS("10")                       //
    //! runtextmacro BONUSSTATS_COMMENTME()                         //
    //! endexternalblock                                            //
    //                                                              //
    // Usage:                                                       //
    // Set<Stat>Bonus<Ex>(unit whichUnit,integer amount)            //
    // Set<Stat>Bonus<Ex>ById(integer whichUnit,integer amount)     //
    // Get<Stat>Bonus(unit whichUnit)->integer                      //
    // Get<Stat>BonusById(integer whichUnit)->integer               //
    // Shift<Stat>Bonus<Ex>(unit whichUnit)->integer                //
    // Shift<Stat>Bonus<Ex>ById(integer whichUnit)->integer         //
    //      -Stats: Armor/Damage/Strength/Intelligence/Strength     //
    //      -Ex supports negative numbers                           //
    //                                                              //
    //////////////////////////////////////////////////////////////////
   
    // ---------------
   
    globals
        private integer cap                     // 2^maxBit-1
    endglobals
   
    // ---------------
   
    //! runtextmacro BONUSSTATS_FUNCTIONS("Damage","d")
    //! runtextmacro BONUSSTATS_FUNCTIONS("Armor","a")
    //! runtextmacro BONUSSTATS_FUNCTIONS("Strength","s")
    //! runtextmacro BONUSSTATS_FUNCTIONS("Agility","g")
    //! runtextmacro BONUSSTATS_FUNCTIONS("Intelligence","t")
   
    // ---------------
   
    //! textmacro BONUSSTATS_FUNCTIONS takes ALIAS, ARR
        globals
            private integer array $ARR$     // current bonus
            private integer array $ARR$Id   // ability id array
        endglobals
        // Removes/Adds aId[observed bit] depending on bit states of $ARR$[u]/m
        function Set$ALIAS$BonusById takes integer u, integer m returns nothing
            local integer b=0
            local integer i=m
            local integer j=$ARR$[u]
            debug if(maxBit<31 and IAbsBJ(m)>cap)then
            debug   call BJDebugMsg("|cffff0000Set$ALIAS$BonusById ERROR: Input out of bounds ("+I2S(m)+")")
            debug   return
            debug elseif(m<0)then
            debug   call BJDebugMsg("|cffff0000Set$ALIAS$BonusById ERROR: Input negative, use Set$ALIAS$Bonus<ById>Ex")
            debug   return
            debug elseif(j<0)then
            debug   call BJDebugMsg("|cffff0000Set$ALIAS$BonusById ERROR: Present value negative, use Set$ALIAS$Bonus<ById>Ex")
            debug   return
            debug endif
            loop
                if(i/2*2==i)then //inactive i
                    if(j/2*2!=j)then //active j => REMOVE
                        call UnitRemoveAbility(GetIndexUnit(u),$ARR$Id[b])
                    endif
                elseif(j/2*2==j)then //active i, inactive j => ADD
                    call UnitAddAbility(GetIndexUnit(u),$ARR$Id[b])
                endif
                set i=i/2 //right shift
                set j=j/2 //right shift
                exitwhen(j==i) //no reason to continue if same numbers
                set b=b+1 //next bit
            endloop
            set $ARR$[u]=m
        endfunction
       
        // Calls function above with some safety, inlines when not in debug mode
        function Set$ALIAS$Bonus takes unit u, integer m returns nothing
            debug if(GetUnitUserData(u)==0)then
            debug   call BJDebugMsg("|cffff0000Set$ALIAS$Bonus ERROR: Removed/unindexed unit given")
            debug   return
            debug endif
            call Set$ALIAS$BonusById(GetUnitId(u),m)
        endfunction
       
        // Same as Set$ALIAS$BonusById, but checks for left-most bit (msb)
        function Set$ALIAS$BonusExById takes integer u, integer m returns nothing
            local integer b=0
            local integer i=m
            local integer j=$ARR$[u]
            debug if(maxBit<31 and IAbsBJ(m)>cap)then
            debug   call BJDebugMsg("|cffff0000Set$ALIAS$BonusById ERROR: Input out of bounds ("+I2S(m)+")")
            debug   return
            debug endif
            if(i<0)then
                set i=cap+i
                if(j<0)then
                    set j=cap+j
                else
                    call UnitAddAbility(GetIndexUnit(u),'a$ARR$bv')
                endif
            elseif(j<0)then
                call UnitRemoveAbility(GetIndexUnit(u),'a$ARR$bv')
                set j=cap+j
            endif
            loop
                if(i/2*2==i)then //inactive i
                    if(j/2*2!=j)then //active j => REMOVE
                        call UnitRemoveAbility(GetIndexUnit(u),$ARR$Id[b])
                    endif
                elseif(j/2*2==j)then //active i, inactive j => ADD
                    call UnitAddAbility(GetIndexUnit(u),$ARR$Id[b])
                endif
                set i=i/2 //right shift
                set j=j/2 //right shift
                exitwhen(j==i) //no reason to continue if same numbers
                set b=b+1 //next bit
            endloop
            set $ARR$[u]=m
        endfunction
       
        // Calls function above with some safety, inlines when not in debug mode
        function Set$ALIAS$BonusEx takes unit u, integer m returns nothing
            debug if(GetUnitUserData(u)==0)then
            debug   call BJDebugMsg("|cffff0000Set$ALIAS$BonusEx ERROR: Removed/unindexed unit given")
            debug   return
            debug endif
            call Set$ALIAS$BonusExById(GetUnitId(u),m)
        endfunction
       
        // Returns value stored in n
        function Get$ALIAS$BonusById takes integer u returns integer
            return $ARR$[u]
        endfunction
       
        // Calls function above with some safety, inlines when not in debug mode
        function Get$ALIAS$Bonus takes unit u returns integer
            debug if(GetUnitUserData(u)==0)then
            debug   call BJDebugMsg("|cffffff00Get$ALIAS$Bonus WARNING: Removed/unindexed unit given")
            debug   return 0
            debug endif
            return Get$ALIAS$BonusById(GetUnitId(u))
        endfunction
       
        // Shifts stat by given integer n
        function Shift$ALIAS$BonusExById takes integer u,integer n returns nothing
            call Set$ALIAS$BonusExById(u,Get$ALIAS$BonusById(u)+n)
        endfunction
       
        // Calls function above with some safety, inlines when not in debug mode
        function Shift$ALIAS$BonusEx takes unit u,integer n returns nothing
            debug if(GetUnitUserData(u)==0)then
            debug   call BJDebugMsg("|cffffff00Shift$ALIAS$BonusEx WARNING: Removed/unindexed unit given")
            debug   return
            debug endif
            call Shift$ALIAS$BonusExById(GetUnitId(u),n)
        endfunction
       
        // Shifts stat by given integer n
        function Shift$ALIAS$BonusById takes integer u,integer n returns nothing
            call Set$ALIAS$BonusById(u,Get$ALIAS$BonusById(u)+n)
        endfunction
       
        // Calls function above with some safety, inlines when not in debug mode
        function Shift$ALIAS$Bonus takes unit u,integer n returns nothing
            debug if(GetUnitUserData(u)==0)then
            debug   call BJDebugMsg("|cffffff00Shift$ALIAS$Bonus WARNING: Removed/unindexed unit given")
            debug   return
            debug endif
            call Shift$ALIAS$BonusById(GetUnitId(u),n)
        endfunction
    //! endtextmacro
   
    // ---------------
   
    private keyword Init
   
    private struct S extends array
   
        // Deindexed units are at unrecoverable state => no need to remove added abilities
        static method AIDS_onDeallocate takes nothing returns boolean
            set d[AIDS_GetDecayingIndex()]=0
            set a[AIDS_GetDecayingIndex()]=0
            return false
        endmethod
   
        implement Init
   
    endstruct
   
    // ---------------
   
    private module Init
       
        static method onInit takes nothing returns nothing
       
            local unit u=CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),'hfoo',0,0,0)
            local integer i=0
            local integer j=1
            loop
                exitwhen(maxBit==i)
                if(i==30)then
                    debug call BJDebugMsg("|cffffff00DamageBonus WARNING: Max bit out of bounds ("+I2S(maxBit-30)+" unusued object(s) generated, inproper Ex object)")
                    exitwhen(true)
                endif
                set j=j*2
                set i=i+1
            endloop
            set cap=j-1
           
            call AIDS_RegisterOnDeallocate(Filter(function thistype.AIDS_onDeallocate))
           
            //! runtextmacro BONUSSTATS_INIT("d")
            //! runtextmacro BONUSSTATS_INIT("a")
            //! runtextmacro BONUSSTATS_INIT("s")
            //! runtextmacro BONUSSTATS_INIT("g")
            //! runtextmacro BONUSSTATS_INIT("t")
           
            loop
                call UnitAddAbility(u,dId[i])
                call UnitAddAbility(u,aId[i])
                call UnitAddAbility(u,sId[i])
                call UnitAddAbility(u,gId[i])
                call UnitAddAbility(u,tId[i])
                exitwhen(i==0)
                set i=i-1
            endloop
            call UnitAddAbility(u,'adbv')
            call UnitAddAbility(u,'aabv')
            call UnitAddAbility(u,'asbv')
            call UnitAddAbility(u,'agbv')
            call UnitAddAbility(u,'atbv')
            call RemoveUnit(u)
           
            set u=null
           
        endmethod
       
    endmodule
   
    //! textmacro BONUSSTATS_INIT takes ARR

        set $ARR$Id[0]='a$ARR$b0'
        set $ARR$Id[1]='a$ARR$b1'
        set $ARR$Id[2]='a$ARR$b2'
        set $ARR$Id[3]='a$ARR$b3'
        set $ARR$Id[4]='a$ARR$b4'
        set $ARR$Id[5]='a$ARR$b5'
        set $ARR$Id[6]='a$ARR$b6'
        set $ARR$Id[7]='a$ARR$b7'
        set $ARR$Id[8]='a$ARR$b8'
        set $ARR$Id[9]='a$ARR$b9'
        set $ARR$Id[10]='a$ARR$ba'
        set $ARR$Id[11]='a$ARR$bb'
        set $ARR$Id[12]='a$ARR$bc'
        set $ARR$Id[13]='a$ARR$bd'
        set $ARR$Id[14]='a$ARR$be'
        set $ARR$Id[15]='a$ARR$bf'
        set $ARR$Id[16]='a$ARR$bg'
        set $ARR$Id[17]='a$ARR$bh'
        set $ARR$Id[18]='a$ARR$bi'
        set $ARR$Id[19]='a$ARR$bj'
        set $ARR$Id[20]='a$ARR$bk'
        set $ARR$Id[21]='a$ARR$bl'
        set $ARR$Id[22]='a$ARR$bm'
        set $ARR$Id[23]='a$ARR$bn'
        set $ARR$Id[24]='a$ARR$bo'
        set $ARR$Id[25]='a$ARR$bp'
        set $ARR$Id[26]='a$ARR$bq'
        set $ARR$Id[27]='a$ARR$br'
        set $ARR$Id[28]='a$ARR$bs'
        set $ARR$Id[29]='a$ARR$bt'
        set $ARR$Id[30]='a$ARR$bu'
           
    //! endtextmacro
   
    // ---------------
   
    //! textmacro BONUSSTATS_OBJECTS takes MAXBIT
   
        globals
            private constant integer maxBit=$MAXBIT$
        endglobals
           
        //! externalblock extension=lua ObjectMerger $FILENAME$
            //! i local max=$MAXBIT$
           
    //! endtextmacro
    //! textmacro BONUSSTATS_COMMENTME
   
            //! i local idd = {"adb0", "adb1", "adb2", "adb3", "adb4", "adb5", "adb6", "adb7", "adb8", "adb9", "adba", "adbb", "adbc", "adbd", "adbe", "adbf", "adbg", "adbh", "adbi", "adbj", "adbk", "adbl", "adbm", "adbn", "adbo", "adbp", "adbq", "adbr", "adbs", "adbt", "adbu"}
            //! i local ida = {"aab0", "aab1", "aab2", "aab3", "aab4", "aab5", "aab6", "aab7", "aab8", "aab9", "aaba", "aabb", "aabc", "aabd", "aabe", "aabf", "aabg", "aabh", "aabi", "aabj", "aabk", "aabl", "aabm", "aabn", "aabo", "aabp", "aabq", "aabr", "aabs", "aabt", "aabu"}
            //! i local ids = {"asb0", "asb1", "asb2", "asb3", "asb4", "asb5", "asb6", "asb7", "asb8", "asb9", "asba", "asbb", "asbc", "asbd", "asbe", "asbf", "asbg", "asbh", "asbi", "asbj", "asbk", "asbl", "asbm", "asbn", "asbo", "asbp", "asbq", "asbr", "asbs", "asbt", "asbu"}
            //! i local idg = {"agb0", "agb1", "agb2", "agb3", "agb4", "agb5", "agb6", "agb7", "agb8", "agb9", "agba", "agbb", "agbc", "agbd", "agbe", "agbf", "agbg", "agbh", "agbi", "agbj", "agbk", "agbl", "agbm", "agbn", "agbo", "agbp", "agbq", "agbr", "agbs", "agbt", "agbu"}
            //! i local idi = {"atb0", "atb1", "atb2", "atb3", "atb4", "atb5", "atb6", "atb7", "atb8", "atb9", "atba", "atbb", "atbc", "atbd", "atbe", "atbf", "atbg", "atbh", "atbi", "atbj", "atbk", "atbl", "atbm", "atbn", "atbo", "atbp", "atbq", "atbr", "atbs", "atbt", "atbu"}
           
            //! i setobjecttype("abilities")
           
            //! i for i=0, max-1 do
           
                //! i createobject("AItg",idd[i+1])
                //! i makechange(current,"aart","")
                //! i makechange(current,"Iatt",1,math.pow(2,i))
                //! i makechange(current,"ansf","+" .. math.pow(2,i))
                //! i makechange(current,"anam","DamageBonus")
               
                //! i createobject("AId1",ida[i+1])
                //! i makechange(current,"Idef",1,math.pow(2,i))
                //! i makechange(current,"ansf","+" .. math.pow(2,i))
                //! i makechange(current,"anam","ArmorBonus")
               
                //! i createobject("AIs3",ids[i+1])
                //! i makechange(current,"Istr",1,math.pow(2,i))
                //! i makechange(current,"ansf","+" .. math.pow(2,i))
                //! i makechange(current,"anam","StrengthBonus")
               
                //! i createobject("AIa3",idg[i+1])
                //! i makechange(current,"Iagi",1,math.pow(2,i))
                //! i makechange(current,"ansf","+" .. math.pow(2,i))
                //! i makechange(current,"anam","AgilityBonus")
               
                //! i createobject("AIi3",idi[i+1])
                //! i makechange(current,"Iint",1,math.pow(2,i))
                //! i makechange(current,"ansf","+" .. math.pow(2,i))
                //! i makechange(current,"anam","IntelligenceBonus")
               
            //! i end
           
            //! i createobject("AItg","adbv")
            //! i makechange(current,"aart","")
            //! i makechange(current,"Iatt",1,-math.pow(2,max)+1)
            //! i makechange(current,"ansf","-" .. math.pow(2,max)-1)
            //! i makechange(current,"anam","DamageBonus")
           
            //! i createobject("AId1","aabv")
            //! i makechange(current,"Idef",1,-math.pow(2,max)+1)
            //! i makechange(current,"ansf","-" .. math.pow(2,max)-1)
            //! i makechange(current,"anam","ArmorBonus")
           
            //! i createobject("AIs3","asbv")
            //! i makechange(current,"Istr",1,-math.pow(2,max)+1)
            //! i makechange(current,"ansf","-" .. math.pow(2,max)-1)
            //! i makechange(current,"anam","StrengthBonus")
           
            //! i createobject("AIa3","agbv")
            //! i makechange(current,"Iagi",1,-math.pow(2,max)+1)
            //! i makechange(current,"ansf","-" .. math.pow(2,max)-1)
            //! i makechange(current,"anam","AgilityBonus")
           
            //! i createobject("AIi3","atbv")
            //! i makechange(current,"Iint",1,-math.pow(2,max)+1)
            //! i makechange(current,"ansf","-" .. math.pow(2,max)-1)
            //! i makechange(current,"anam","IntelligenceBonus")
           
    //! endtextmacro
   
endlibrary
 
Top