• 🏆 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!

[System] Stat Manipulation

Level 29
Joined
Oct 24, 2012
Messages
6,543
hello i have made a system for stat manipulation of heroes since i was getting annoyed w doing the math every time and trying to keep track of abilities that stacked. i think it is done but as i expect it may need improvements. it is an easy system to implement. it keeps track of all the stat manipulations u want it to. it is easy to reset the stats back after the ability has ended.
it can keep track of custom stat reductions like when unit enters region just give the abiID integer ur own custom integer ( be careful w overwriting doing it this way ). you can set a variable so when a unit is killed it can remove all stat modifications automatically. i may add some features to this but as it is its a nice simple system. this will not be affected by lvls gained, tomes, items added or dropped, or anything of tht sort. you can make the system be affected by items if u want to trigger the item stats. ( although i do not see this ever being done)


if anyone finds any bugs / improvements plz tell me.

JASS:
library StatManipulationSystem /* version 1.0.2.5
================================ Requirements =================================
               Requires JNGP 
    */uses Table /* [url]http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/[/url] by bribe
    *      Alloc  * [url]http://www.hiveworkshop.com/forums/jass-resources-412/snippet-alloc-alternative-221493/[/url] by nestharus
    
*************************************************************************************
*
*   Used to keep track of all buffs / debuffs that affect heroes attributes
*
************************************************************************************
*
*   Installing
*       STEP 1: Install JNGP first if you dont have JNGP.
*       STEP 2: Install Table by bribe the link is above.
*       STEP 3: Install Alloc by nestharus the link is above. You may be able to use some other alloc systems.
*       STEP 4: Copy and paste this library to your map.
*
************************************************************************************
*
*   struct UnitStatsManipulation extends array
*
*       Description
*       -----------------------
*           You can use this system to keep track of all your buffs and debuffs that get added to a hero.
*           This is MUI and allows for stacks on basis of ability 1 + ability 2 and so on.
*           This does not allow stacks on basis of ability 1 + ability 1.
*           You do not have to do the math for every spell with this system.
*           If you use hashtables to keep track of stat manipulation in each of ur abilities then this will also save on hashtable space
*
*       Capabilities
*       -----------------------
*           This will keep track of up to 8191 heroes with 1 ability buff / debuff each
*           or This will keep track of 1 hero with 8191 ability buffs / debuffs
*           Heres a number that is more suited to what will be able to happen in a map w 50 heroes
*               -   keeping track of 50 heroes with a max of 163 buffs / debuffs added to each hero
*
*       Creators/Destructors
*       -----------------------
*
*           static method open takes string mapName, string fileName, integer flag returns File
*               -   Used to open a file. Pass read/write flag in to open file for reading or writing.
*
*           method close takes nothing returns nothing
*
*       Fields
*       -----------------------
*
*           private constant boolean REMOVE_STATS_ON_DEATH 
*               - This boolean allows you to remove all buffs / debuffs from unit on death 
*
*       Methods
*       -----------------------
*
*           static method resetStats takes unit u returns nothing
*               -   removes all bonus stats given to the unit by the use of triggers 
*               -   linked with this system of the unit tht it takes
*    
*           static method removeStats takes unit u, integer abiID returns nothing
*               -   when ability is ended call this method and it will remove the bonus stats given to the unit
*               
*           static method addStatsInteger takes unit u, integer abiID, integer agi, integer intel, integer str returns nothing
*               -   adds stats to unit with the use of integers.
*               -   ex: 25 agi, 20 intel, 0 str  =  will add 25 agi, 20 intel and 0 str to ur unit
*               
*           static method addStatsPercent takes unit u, integer abiID, real agi, real intel, real str returns nothing
*               -   adds stats to unit with the use of percents given in reals.   100% is 100.00
*               -   ex: 100.00 agi, 20.00 intel, 1.25 str  =  will add 100% agi, 20% intel and 1.25% str to ur unit
*            
*           static method addStatsByLvlInteger takes unit u, integer abiID, integer agi, integer intel, integer str returns nothing
*               -   adds stats to unit with the use of integers determined by hero lvl.
*               -   ex: 25 agi, 20 intel, 0 str  =  
*                   will add 25 agi, 20 intel and 0 str to ur unit for lvl 1
*                   will add 50 agi, 40 intel and 0 str to ur unit for lvl 2 and so on
*           
*           static method addStatsByLvlPercent takes unit u, integer abiID, real agi, real intel, real str returns nothing
*               -   adds stats to unit with the use of percents given in reals determined by hero lvl.   100% is 100.00
*               -   ex: 100.00 agi, 20.00 intel, 1.25 str  =  
*                   will add 100% agi, 20% intel and 1.25% str to ur unit for lvl 1 and it
*                   will add 200% agi, 40% intel and 2.5% str to ur unit for lvl 2 and so on
*
*************************************************************************************/    

    globals
        private constant boolean REMOVE_STATS_ON_DEATH = true // change this to false if u do not want this to happen
        private Table unitTable
        private Table abilityTable
    endglobals

    private struct bonuses extends array
        implement Alloc
            
        integer bAgi
        integer bStr
        integer bInt
        
        static method create takes unit u, integer id, integer agi, integer intel, integer str returns thistype
            local thistype this = thistype.allocate()
            set abilityTable[ GetHandleId( u)][ id] = this
            set this.bAgi = agi
            set this.bInt = intel
            set this.bStr = str
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            call this.deallocate()
        endmethod
        
    endstruct

    struct UnitStatsManipulation extends array
        implement Alloc
        
        private integer uAgi
        private integer uStr
        private integer uInt
        private integer uID
        private integer abilityCounter
        private unit u
        private integer allBonusesAgi
        private integer allBonusesStr
        private integer allBonusesInt
        private boolean statRemovalCheck
        
        static method resetStats takes unit u returns nothing
            local thistype this = unitTable[ GetHandleId( u)]
            set this.statRemovalCheck = false
            call SetHeroAgi( this.u, GetHeroAgi( this.u, true) - allBonusesAgi, true)
            call SetHeroInt( this.u, GetHeroInt( this.u, true) - allBonusesInt, true)
            call SetHeroStr( this.u, GetHeroStr( this.u, true) - allBonusesStr, true)
            set this.u = null
        endmethod
        
        static method removeStats takes unit u, integer id returns nothing
            local bonuses data = abilityTable[ GetHandleId( u)][ id]
            local thistype this = unitTable[ GetHandleId( u)]
            if this.statRemovalCheck == true then
                call SetHeroAgi( this.u, GetHeroAgi( this.u, true) - data.bAgi, true)
                call SetHeroInt( this.u, GetHeroInt( this.u, true) - data.bInt, true)
                call SetHeroStr( this.u, GetHeroStr( this.u, true) - data.bStr, true)
                set this.abilityCounter = this.abilityCounter - 1
                call data.destroy()
                call abilityTable.remove( GetHandleId( u))
                call abilityTable.remove( id)
                if this.abilityCounter == 0 then
                    call this.destroy()
                endif
            endif
        endmethod
        
        static method addStatsInteger takes unit u, integer id, integer agi, integer intel, integer str returns nothing
            local thistype this = unitTable[ GetHandleId( u)]
            if not abilityTable.has( id) then
                call addStats( agi, intel, str)
                call bonuses.create( u, id, agi, intel, str)
            endif
        endmethod
        
        static method addStatsPercent takes unit u, integer id, real agi, real intel, real str returns nothing
            local thistype this = unitTable[ GetHandleId( u)]
            local integer a = R2I(this.uAgi * ( agi/100))
            local integer i = R2I(this.uAgi * ( intel/100))
            local integer s = R2I(this.uAgi * ( str/100))
            if not abilityTable.has( id) then
                call addStats( a, i, s)
                call bonuses.create( u, id, a, i, s)
            endif
        endmethod
        
        static method addStatsByLvlInteger takes unit u, integer id, integer agi, integer intel, integer str returns nothing
            local thistype this = unitTable[ GetHandleId( u)]
            local integer lvl = GetHeroLevel( u)
            if not abilityTable.has( id) then
                set agi = agi*lvl
                set intel = intel*lvl
                set str = str*lvl
                call addStats( agi, intel, str)
                call bonuses.create( u, id, agi, intel, str)
            endif
        endmethod
        
        static method addStatsByLvlPercent takes unit u, integer id, real agi, real intel, real str returns nothing
            local thistype this = unitTable[ GetHandleId( u)]
            local integer lvl = GetHeroLevel( u)
            local integer a = lvl*R2I(this.uAgi * ( agi/100))
            local integer i = lvl*R2I(this.uAgi * ( intel/100))
            local integer s = lvl*R2I(this.uAgi * ( str/100))
            if not abilityTable.has( id) then
                call addStats( a, i, s)
                call bonuses.create( u, id, a, i, s)
            endif
        endmethod
        
        private method addStats takes integer a, integer i, integer s returns nothing
            set this.statRemovalCheck = true
            set this.allBonusesAgi = this.allBonusesAgi + a
            set this.allBonusesStr = this.allBonusesInt + i
            set this.allBonusesInt = this.allBonusesStr + s
            set this.abilityCounter = this.abilityCounter + 1
            call SetHeroAgi( this.u, GetHeroAgi( this.u, true) + a, true)
            call SetHeroInt( this.u, GetHeroInt( this.u, true) + i, true)
            call SetHeroStr( this.u, GetHeroStr( this.u, true) + s, true)
        endmethod
        
        static method create takes unit u returns thistype
            local thistype this = thistype.allocate()
            local integer id = GetHandleId( u)
            set this.uID = id
            set this.u = u
            set unitTable[ id] = this
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            call unitTable.remove( this.uID)
            set this.u = null
            call this.deallocate()
        endmethod
        
        private static method remove takes nothing returns boolean
            local thistype this = unitTable[ GetHandleId( GetTriggerUnit())]
            if REMOVE_STATS_ON_DEATH then
                set this.statRemovalCheck = false
                call SetHeroAgi( this.u, GetHeroAgi( this.u, true) - allBonusesAgi, true)
                call SetHeroInt( this.u, GetHeroInt( this.u, true) - allBonusesInt, true)
                call SetHeroStr( this.u, GetHeroStr( this.u, true) - allBonusesStr, true)
                set this.u = null
                call this.destroy()
            endif
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_DEATH)
            call TriggerAddCondition( t, function thistype.remove)
            set unitTable = Table.create()
            set abilityTable = TableArray[0x2000]
        endmethod
        
    endstruct

endlibrary


version 1.0.2.5
fixed indentation​
version 1.0.2.0
update API for better readability
forgot to remove values from Table​
version 1.0.1.0
fixed small bug w removing stats
made the code a little neater​
version 1.0.0.0
first version released​
 
Last edited:
Level 33
Joined
Apr 24, 2012
Messages
5,113
Level 29
Joined
Oct 24, 2012
Messages
6,543
ill try to make the API more interesting lol. i believe there is only one method i could change back to non static which i just did. i made this at 4 am so i was quite tired lol. if there is anything else i can change from static to non static mybe im just not getting it lol. ill remake the API in about an hr or so.
 

Zwiebelchen

Hosted Project GR
Level 35
Joined
Sep 17, 2009
Messages
7,236
I think this should support custom stats and all stats provided by BonusMod aswell. Otherwise its way too unflexible.

I'd say everyone who is considering to do stuff like that should better use BonusMod in combination with the Buff libary instead for higher flexibility and cleaner coding of buffing/debuffing spells.
 
Level 33
Joined
Apr 24, 2012
Messages
5,113
Uhmm the indention is still not fixed:
JASS:
    struct UnitStatsManipulation extends array
    implement Alloc
    
    private integer uAgi
    private integer uStr
    private integer uInt
    private integer uID
    private integer abilityCounter
    private unit u
    private integer allBonusesAgi
    private integer allBonusesStr
    private integer allBonusesInt
    private boolean statRemovalCheck

Same With
JASS:
    private struct bonuses extends array
    implement Alloc
        
    integer bAgi
    integer bStr
    integer bInt
I forgot to mention.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Alloc is required, but outcommented.

Install Table by bribe the link is above.
( You mean copy, not install ) poor Bribe written small.

Should use a module initializer. For safety reason you should always initialize non array globals like for example your Table instance.
Otherwise the thread may break if onInit didn't run already.

code using REMOVE_STATS_ON_DEATH should be written in static ifs

UnitStatsManipulation.addStatsByLvlInteger(...) is freaking long method name. ( integer? )

Every method in your struct is static, so why not go with simple functions instead?

if this.statRemovalCheck == true then Going back to the Stone Age of wc3 coding?

set abilityTable = TableArray[0x2000] --> abilityTable is a Table type and TableArray[] returns TableArray!

????
JASS:
*       Creators/Destructors
*       -----------------------
*
*           static method open takes string mapName, string fileName, integer flag returns File
*               -   Used to open a file. Pass read/write flag in to open file for reading or writing.
*
*           method close takes nothing returns nothing

There is much more very wrong! I give you some time to defend your resource.
Otherwise it is going to the graveyard.
 
Top