1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. We have recently started the 16th edition of the Mini Mapping Contest. The theme is mini RPG. Do check it out and have fun.
    Dismiss Notice
  4. Choose your ride to damnation in the 5th Special Effect Contest Poll.
    Dismiss Notice
  5. The winners of the 13th Techtree Contest have been announced!
    Dismiss Notice
  6. The 13th Music Contest Poll is up! Vote for the best tracks in this symphony of frost and flame.
    Dismiss Notice
  7. Race against the odds and Reforge, Don't Refund. The 14th Techtree Contest has begun!
    Dismiss Notice
  8. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

BonusHandler

Discussion in 'Wurst Resources' started by muzzel, Oct 18, 2013.

  1. muzzel

    muzzel

    Joined:
    Jun 27, 2008
    Messages:
    1,303
    Resources:
    2
    JASS:
    1
    Wurst:
    1
    Resources:
    2
    [WurstScript] BonusHandler 1.5

    BonusHandler is a library for WurstScript which provides an easy way to manipulate unit bonuses via trigger, similar to BonusMod for vJass.

    Available bonuses:
    • Life
    • Mana
    • Damage
    • Armor
    • Sightrange
    • Liferegen
    • Manaregen (percental or absolute)
    • Attackspeed
    • Strength
    • Agility
    • Intelligence

    There are no requirements except for the obligatory WurstScript StandardLib.

    The required objectdata gets generated by WurstScripts Objectediting-Compiletimenatives. Unlike the JNGP objectmerger the WurstScript objectgeneration doesnt require LUA, subsequently it works with newer operating systems where LUA is broken.

    Code:
    Code (WurstScript):

    package BonusHandlerConfig
    /**
    * Values are the exponents to base 2.
    * 2^9=512, 2^10=1024, 2^11=2048, 2^12=4096 etc.
    */


    public constant MAX_BONUS_LIFE = 12
    public constant MAX_BONUS_MANA = 12
    public constant MAX_BONUS_DAMAGE = 10
    public constant MAX_BONUS_ARMOR = 10
    public constant MAX_BONUS_SIGHTRANGE = 11
    public constant MAX_BONUS_LIFEREGEN = 4
    public constant MAX_BONUS_MANAREGEN = 10
    public constant MAX_BONUS_ATTACKSPEED = 9
    public constant MAX_BONUS_STRENGTH = 9
    public constant MAX_BONUS_AGILITY = 9
    public constant MAX_BONUS_INTELLIGENCE = 9
    public constant IS_MANAREGEN_PERCENTAL = false
     

    Code (WurstScript):

    package BonusHandler
    // Version 1.5 - Credits: Frotty, Overkane, muzzel, Crigges, Earth-Fury, Halithor
    import BonusHandlerConfig
    import AbilityObjEditing
    import ObjectIds
    import Preloader

    int array powersOf2
    int array rawShifts
    int rawShiftNeg
    BonusType array bonusTypes

    public enum Bonus
         LIFE
         MANA
        DAMAGE
        ARMOR
        SIGHTRANGE
        LIFEREGEN
        MANAREGEN
        ATTACKSPEED
        STRENGTH
        AGILITY
        INTELLIGENCE

    //Gets the current bonus value
    public function getUnitBonus(unit u, Bonus bonusType) returns int
        let bonus = bonusTypes[bonusType castTo int]
        var result = 0
        if u.hasAbility(bonus.baseRaw + rawShiftNeg)
             result -= powersOf2[bonus.maxBonus]
        for i = 0 to bonus.maxBonus - 1
             result += u.hasAbility(bonus.baseRaw + shiftRaw(i)) ? powersOf2[i] : 0
        return result

    //Adds to current bonus bonusValue
    public function addUnitBonus(unit u, Bonus bonusType, int bonusValue)
        int currentBonusValue = getUnitBonus(u, bonusType)
        int afterBonusValue = currentBonusValue + bonusValue
        setUnitBonus(u, bonusType, afterBonusValue)

    /** Sets the bonus of specified type for the unit to the given amount. */
    public function setUnitBonus(unit u, Bonus bonusType, int amount)
        bonusTypes[bonusType castTo int].setBonus(u, amount)

    /** Sets the bonus of specified type for the unit to zero. */
    public function clearUnitBonus(unit u, Bonus bonusType)
        bonusTypes[bonusType castTo int].clearBonus(u)

    /** Gets the highest applicable value for the specified bonus type. */
    public function getMaxBonus(Bonus bonusType) returns int
        return powersOf2[bonusTypes[bonusType castTo int].maxBonus - 1]

    /** Gets the smallest applicable value for the specified bonus type. */
    public function getMinBonus(Bonus bonusType) returns int
        return -powersOf2[bonusTypes[bonusType castTo int].maxBonus]

    /** Removes all bonuses from the specified unit. */
    public function clearAllUnitBonuses(unit u)
        bonusTypes[Bonus.LIFE castTo int].clearBonus(u)
        bonusTypes[Bonus.MANA castTo int].clearBonus(u)
        bonusTypes[Bonus.DAMAGE castTo int].clearBonus(u)
        bonusTypes[Bonus.ARMOR castTo int].clearBonus(u)
        bonusTypes[Bonus.SIGHTRANGE castTo int].clearBonus(u)
        bonusTypes[Bonus.LIFEREGEN castTo int].clearBonus(u)
        bonusTypes[Bonus.MANAREGEN castTo int].clearBonus(u)
        bonusTypes[Bonus.ATTACKSPEED castTo int].clearBonus(u)
        bonusTypes[Bonus.STRENGTH castTo int].clearBonus(u)
        bonusTypes[Bonus.AGILITY castTo int].clearBonus(u)
        bonusTypes[Bonus.INTELLIGENCE castTo int].clearBonus(u)


    /** Enumeration of the bonustypes. */
    class BonusType
        int baseRaw
        int maxBonus

        construct(int baseRaw, int maxBonus)
             this.baseRaw = baseRaw
             this.maxBonus = maxBonus

        function setBonus(unit u, int bonus)
             if bonus >= powersOf2[maxBonus]
                  printLog(Loglevel.WARNING, "Bonus exceeds maximum")
                  return
             if bonus < -powersOf2[maxBonus]
                  printLog(Loglevel.WARNING, "Bonus exceeds maximum")
                  return
         
             int val
             bool addNeg = false
             var raw = baseRaw + rawShiftNeg
             if bonus < 0
                  addNeg = true
                  val = bonus + powersOf2[maxBonus]
             else
                  val = bonus
                  UnitMakeAbilityPermanent(u, false, raw)
                  u.removeAbility(raw)
             
             for n = maxBonus-1 downto 0
                  raw = baseRaw + rawShifts[n]
                  if val >= powersOf2[n]
                        u.addAbility(raw)
                        UnitMakeAbilityPermanent(u, true, raw)
                        val -= powersOf2[n]
                  else
                        UnitMakeAbilityPermanent(u, false, raw)
                        u.removeAbility(raw)
             // Add negative last to avoid setting stat to <0 (killing the unit, etc)
             if addNeg
                  u.addAbility(baseRaw + rawShiftNeg)
                  UnitMakeAbilityPermanent(u, true, baseRaw + rawShiftNeg)

        function clearBonus(unit u)
             var raw = baseRaw + rawShiftNeg
             u.makeAbilityPermanent(raw, false)
             u.removeAbility(raw)
             for n = 0 to maxBonus-1
                  raw = baseRaw + rawShifts[n]
                  u.makeAbilityPermanent(raw, false)
                  u.removeAbility(raw)
         

    /** Example: 'XY00' + shiftRaw(15) -> 'XY15' */
    function shiftRaw(int n) returns int
        if n < 10
             return n
        else
             return (n div 10) * 256 + n.moduloInt(10)


    /** Example: pow2(x) -> 2^x */
    function pow2(int e) returns int
        if e == 0
             return 1
        return 2 * pow2(e-1)

    function setProperties(AbilityDefinition a, string suffix, string bonusName)
        a.setItemAbility(false)
        a.setEditorSuffix("(" + suffix + ")")
        a.setIconNormal("ReplaceableTextures\\CommandButtons\\BTNPenguin.blp")
        a.setName("BonusHandler - " + bonusName)


    init
        for n = 0 to 30 // if u need bonuses higher than 1 billion u should rethink your map design...
             powersOf2[n] = Pow(2, n.toReal()).toInt()
        for n = 0 to 30
             rawShifts[n] = shiftRaw(n)
        rawShiftNeg = '00--' - '0000'

        bonusTypes[Bonus.LIFE castTo int] = new BonusType('$L00', MAX_BONUS_LIFE)
        bonusTypes[Bonus.MANA castTo int] = new BonusType('$M00', MAX_BONUS_MANA)
        bonusTypes[Bonus.DAMAGE castTo int] = new BonusType('$D00', MAX_BONUS_DAMAGE)
        bonusTypes[Bonus.ARMOR castTo int] = new BonusType('$R00', MAX_BONUS_ARMOR)
        bonusTypes[Bonus.SIGHTRANGE castTo int] = new BonusType('$V00', MAX_BONUS_SIGHTRANGE)
        bonusTypes[Bonus.LIFEREGEN castTo int] = new BonusType('$l00', MAX_BONUS_LIFEREGEN)
        bonusTypes[Bonus.MANAREGEN castTo int] = new BonusType('$m00', MAX_BONUS_MANAREGEN)
        bonusTypes[Bonus.ATTACKSPEED castTo int] = new BonusType('$P00', MAX_BONUS_ATTACKSPEED)
        bonusTypes[Bonus.STRENGTH castTo int] = new BonusType('$S00', MAX_BONUS_STRENGTH)
        bonusTypes[Bonus.AGILITY castTo int] = new BonusType('$A00', MAX_BONUS_AGILITY)
        bonusTypes[Bonus.INTELLIGENCE castTo int] = new BonusType('$I00', MAX_BONUS_INTELLIGENCE)

    @compiletime function genAbilities()
        string rawCode
        // Life:
        rawCode = "$L"
        for n = 0 to MAX_BONUS_LIFE
             string raw
             int sign = 1
             if n < MAX_BONUS_LIFE
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             let a = new AbilityDefinitionMaxLifeBonusLeast(fourchar2int(raw))
             a.setMaxLifeGained(1, sign * pow2(n))
             setProperties(a, I2S(sign * pow2(n)), "Life")
         
        // Mana:
        rawCode = "$M"
        for n = 0 to MAX_BONUS_MANA
             string raw
             int sign = 1
             if n < MAX_BONUS_MANA
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             let a = new AbilityDefinitionMaxManaBonusMost(fourchar2int(raw))
             a.setMaxManaGained(1, sign * pow2(n))
             setProperties(a, I2S(sign * pow2(n)), "Mana")
        // Damage:
        rawCode = "$D"
        for n = 0 to MAX_BONUS_DAMAGE
             string raw
             int sign = 1
             if n < MAX_BONUS_DAMAGE
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             let a = new AbilityDefinitionAttackBonus(fourchar2int(raw))
             a.setAttackBonus(1, sign * pow2(n))
             setProperties(a, I2S(sign * pow2(n)), "Damage")
         
        // Armor:
        rawCode = "$R"
        for n = 0 to MAX_BONUS_ARMOR
             string raw
             int sign = 1
             if n < MAX_BONUS_ARMOR
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             let a = new AbilityDefinitionDefenseBonusPlus1(fourchar2int(raw))
             a.setDefenseBonus(1, sign * pow2(n))
             setProperties(a, I2S(sign * pow2(n)), "Armor")

        // Sightrange:
        rawCode = "$V"
        for n = 0 to MAX_BONUS_SIGHTRANGE
             string raw
             int sign = 1
             if n < MAX_BONUS_SIGHTRANGE
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             let a = new AbilityDefinitionSightBonus(fourchar2int(raw))
             a.setSightRangeBonus(1, sign * pow2(n))
             setProperties(a, I2S(sign * pow2(n)), "Sightrange")

        // Liferegen:
        rawCode = "$l"
        for n = 0 to MAX_BONUS_LIFEREGEN
             string raw
             int sign = 1
             if n < MAX_BONUS_LIFEREGEN
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             let a = new AbilityDefinitionRegenLife(fourchar2int(raw))
             a.setHitPointsRegeneratedPerSecond(1, sign * pow2(n))
             setProperties(a, I2S(sign * pow2(n)), "Liferegen")

        // Manaregen:
        rawCode = "$m"
        for n = 0 to MAX_BONUS_MANAREGEN
             string raw
             int sign = 1
             if n < MAX_BONUS_MANAREGEN
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             if IS_MANAREGEN_PERCENTAL
                  let a = new AbilityDefinitionItemRegenMana(fourchar2int(raw))
                  a.setManaRegenerationBonusasfractionofnormal(1, sign * pow2(n) / 100.)
                  setProperties(a, I2S(sign * pow2(n)) + "%", "Manaregen")
             else
                  let a = new AbilityDefinitionNeutralRegenmanaonly(fourchar2int(raw))
                  a.setPercentage(1, false)
                  a.setAreaofEffect(1, 1)
                  a.setTargetsAllowed(1, "self")
                  a.setAmountRegenerated(1, sign * pow2(n) / 200.)
                  a.setRace(Race.Other)
                  setProperties(a, I2S(sign * pow2(n)), "Manaregen")

        // Attackspeed:
        rawCode = "$P"
        for n = 0 to MAX_BONUS_ATTACKSPEED
             string raw
             int sign = 1
             if n < MAX_BONUS_ATTACKSPEED
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             let a = new AbilityDefinitionAttackSpeedIncrease(fourchar2int(raw))
             a.setAttackSpeedIncrease(1, sign * pow2(n) / 100.)
             setProperties(a, I2S(sign * pow2(n)) + "%", "Attackspeed")

        // Strength:
        rawCode = "$S"
        for n = 0 to MAX_BONUS_STRENGTH
             string raw
             int sign = 1
             if n < MAX_BONUS_STRENGTH
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             let a = new AbilityDefinitionStrengthBonusPlus1(fourchar2int(raw))
             a.setStrengthBonus(1, sign * pow2(n))
             setProperties(a, I2S(sign * pow2(n)), "Strength")

        // Agility:
        rawCode = "$A"
        for n = 0 to MAX_BONUS_AGILITY
             string raw
             int sign = 1
             if n < MAX_BONUS_AGILITY
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             let a = new AbilityDefinitionAgilityBonusPlus1(fourchar2int(raw))
             a.setAgilityBonus(1, sign * pow2(n))
             setProperties(a, I2S(sign * pow2(n)), "Agility")

        // Intelligence:
        rawCode = "$I"
        for n = 0 to MAX_BONUS_INTELLIGENCE
             string raw
             int sign = 1
             if n < MAX_BONUS_INTELLIGENCE
                  raw = rawCode
                  if n < 10
                        raw = raw + "0"
                  raw = raw + I2S(n)
             else
                  raw = rawCode + "--"
                  sign = -1
             let a = new AbilityDefinitionIntelligenceBonusPlus1(fourchar2int(raw))
             a.setIntelligenceBonus(1, sign * pow2(n))
             setProperties(a, I2S(sign * pow2(n)), "Intelligence")
         
    init
        for int i = Bonus.LIFE castTo int to Bonus.INTELLIGENCE castTo int
             for int j = 0 to (bonusTypes[i].maxBonus - 1)
                  preloadAbility(bonusTypes[i].baseRaw + shiftRaw(j))

     


    Changelog:
    1.5 - Fixed a few bugs, thanks @Halithor
    1.4 - Added GetBonus and AddBonus, abilities are now preloaded, works with latest stdlib
    1.3 - Added the possibility to chose between percental and absolute manaregen, added HotDoc-conform documentation.
    1.2 - Fixed the code so it works with the latest Wurst StdLib.
    1.1 - Added bonus for max hp, max mana
    1.0 - Initial release

    Credits:
    - Crigges
    - Earth-Fury
     
    Last edited by a moderator: Mar 5, 2018
  2. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,181
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Do you think it would be beneficial to use ability levels, have abilities with upto four levels?

    Setting max mana/hp is essential for any bonus system.

    BTW, the Paladin died instantly as it had -300 str applied ;)
     
  3. muzzel

    muzzel

    Joined:
    Jun 27, 2008
    Messages:
    1,303
    Resources:
    2
    JASS:
    1
    Wurst:
    1
    Resources:
    2
    I think using levels makes the whole thing slower as adding abilities takes more time the more levels they have. Sure, with more levels you would need less abilities, but still ...
    But if you have a source that confirms otherwise im open to it.

    Setting max hp/mana is essential, i agree, but dont using a different approach than for other stats. Thats why i will release it either as a independent library or add it in a future version (i wanna test some stuff before i write it).

    Negative hp regen also kills the testunits, but whatever - its just a test map :p
     
  4. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    The compiletime functions work now?

    Awesome though, it looks great. Except the code tags, they made my eyes sore and I began to cry.

    Could you use [JASS][/JASS] tags? Or [highlight=java][/highlight] tags (or [highlight=wurst][/highlight] tags, jk lol those don't exist yet). Perhaps Ralle could add them if someone sends him the keywords.
     
  5. muzzel

    muzzel

    Joined:
    Jun 27, 2008
    Messages:
    1,303
    Resources:
    2
    JASS:
    1
    Wurst:
    1
    Resources:
    2
    Yea compiletimefunctions work now. And i love them \o/

    Wurst tags would be great, il talk to peq, maybe he has something for inwarcraft.de (which is vB3 too) that ralle could use.
     
  6. muzzel

    muzzel

    Joined:
    Jun 27, 2008
    Messages:
    1,303
    Resources:
    2
    JASS:
    1
    Wurst:
    1
    Resources:
    2
    Update: Added max life and mana.
     
  7. muzzel

    muzzel

    Joined:
    Jun 27, 2008
    Messages:
    1,303
    Resources:
    2
    JASS:
    1
    Wurst:
    1
    Resources:
    2
    Update: Fixed the code so it works with the latest Wurst StdLib.
     
  8. muzzel

    muzzel

    Joined:
    Jun 27, 2008
    Messages:
    1,303
    Resources:
    2
    JASS:
    1
    Wurst:
    1
    Resources:
    2
    Update: Added the possibility to chose between percental and absolute manaregen, added HotDoc-conform documentation.
     
  9. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,468
    Resources:
    11
    Models:
    3
    Tools:
    1
    Maps:
    5
    Tutorials:
    1
    Wurst:
    1
    Resources:
    11
    Solid work, this should be approved by a mod soonish.
     
  10. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Approved.
     
  11. msongyboi

    msongyboi

    Joined:
    Feb 3, 2013
    Messages:
    272
    Resources:
    4
    Spells:
    4
    Resources:
    4
    so regen's cant be in reals?
     
  12. Raised

    Raised

    Joined:
    May 8, 2016
    Messages:
    57
    Resources:
    0
    Resources:
    0
    Heh. It seems to be a popular idea, to create such system =/
     
  13. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,697
    Resources:
    18
    Maps:
    1
    Spells:
    11
    Tutorials:
    6
    Resources:
    18
    Got a lot of errors when I tried to import it. I assume it is outdated.
     
  14. Trokkin

    Trokkin

    Joined:
    Jan 23, 2015
    Messages:
    98
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    Yep it's outdated since stdlib got updated and many functions have been renamed, but it's the only problem with this (as far as I'm concerned), so you can fix this manually./
    I fixed it by doing this three things:
    - Rename all "printWarning" to just "print"
    - Rename all "idString2IdInteger" to "fourchar2int"
    - Make setRace in manaregen generation took Race.Other instead of raw string (I'm a bit confused they didn't overload it with method that takes string for some reason)

    And then everything seems to be OK.
     
    Last edited: Nov 2, 2017
  15. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,468
    Resources:
    11
    Models:
    3
    Tools:
    1
    Maps:
    5
    Tutorials:
    1
    Wurst:
    1
    Resources:
    11
    Yes, muzzel is pretty much gone. There is an unofficial update to this with add-functions. Will add it later maybe.

    e: Have added add/get bonus functions and some patches by halithor!
     
    Last edited: Mar 2, 2018