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

Library to manage buffs

Status
Not open for further replies.

Deleted member 219079

D

Deleted member 219079

I can't seem to find this anywhere, but PLEASE can someone make a library in vJass to handle buffs? I'd use funtions like:
JASS:
// struct Buff
//readonly boolean on
static Buff create(unit whichUnit, integer abilityid, boolean dispellable, real duration)
void destroy()
void getTime()
void setTime()
So if you used duration of 0, you'd manually stop it. If you had dispellable off, it would automatically recast it if it was removed.

When the buff is no more, boolean "on" would be set to false. So user would have to manually destroy the struct instance, this is to prevent interfering of other instances.

PLEASE, someone has to do this D: I don't have time to do it...
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
the problem is that they can only be virtual, not really visible, since you cant control how long you will have buff on unit, unless you recast it every time.

Buffs are very tricky, because Blizzard never got to actually implement Jass API for buffs, what a shame
 

Deleted member 219079

D

Deleted member 219079

I'm not at home atm, can you post the library here?
 
Level 7
Joined
Oct 11, 2008
Messages
304
Free stuff for you from Xonok

JASS:
//This is the core of the system. It handles perk indexing in order to allow easy use of arrays elsewhere. 
library UnitPerk initializer in
    globals
        hashtable PerkTable = InitHashtable()
        
        integer array UnitPerkType
        unit array UnitPerkOwner
        unit array UnitPerkTarget
        integer array UnitPerkCount
        integer array UnitPerkPointer
        integer array UnitPerkNext
        integer array UnitPerkPrev
    
        integer array UnDex
        integer UnDexes
        
        integer ToDestroy
        
        constant integer PERK_DESTROY = 1
    endglobals
    
    function DestroyPerk takes integer index returns nothing
        set ToDestroy = index
        call TriggerEvaluate(LoadTriggerHandle(PerkTable,UnitPerkType[index],PERK_DESTROY))
    endfunction
    
    function InitPerk takes integer perktype,unit target,unit owner returns integer
        //Necessary data
        local integer ID = GetUnitUserData(target)
        //Taking a perk ID from the stack and unallocating the taken ID to prevent overlap
        local integer index = UnDex[UnDexes]
        set UnDexes = UnDexes - 1
        
        //Initializing the perk
        set UnitPerkType[index] = perktype
        set UnitPerkOwner[index] = owner
        set UnitPerkTarget[index] = target
        
        //Incrementing the buff counter(ability level)
        if GetUnitAbilityLevel(target,perktype) > 0 then
            call BJDebugMsg(I2S(GetUnitAbilityLevel(target,perktype)))
            call IncUnitAbilityLevel(target,perktype)
            //call SetUnitAbilityLevel(target,perktype,GetUnitAbilityLevel(target,perktype)+1)
            call BJDebugMsg(I2S(GetUnitAbilityLevel(target,perktype)))
            //call IncUnitAbilityLevel(target,perktype)
        else
            call UnitAddAbility(target,perktype)
        endif
        
        if UnitPerkCount[ID] == 0 then
            //Starting a new doubly linked list
            set UnitPerkCount[ID] = 1
            
            set UnitPerkPointer[ID] = index
            set UnitPerkNext[index] = index
            set UnitPerkPrev[index] = index
        else
            set UnitPerkCount[ID] = UnitPerkCount[ID] + 1
            
            //Swapping the new perk with the one at the pointer. 
            set UnitPerkPrev[UnitPerkPointer[ID]] = index
            set UnitPerkNext[UnitPerkPrev[UnitPerkPointer[ID]]] = index
            //
            set UnitPerkPrev[index] = UnitPerkPrev[UnitPerkPointer[ID]]
            set UnitPerkNext[index] = UnitPerkPointer[ID]
            
            //Setting the pointer to the new perk.
            set UnitPerkPointer[ID] = index
            
        endif
        
        //Return the new perk in order to allow attaching data to it. 
        debug call BJDebugMsg("Array index of new perk is: "+I2S(index))
        return index
    endfunction
    
    function ClearPerk takes integer index returns nothing
        //Necessary for cleaning up
        local unit target = UnitPerkTarget[index]
        local integer perktype = UnitPerkType[index]
        local integer ID = GetUnitUserData(target)
        
        //Decrementing the buff counter(ability level)
        if GetUnitAbilityLevel(target,perktype) > 1 then
            call BJDebugMsg(I2S(GetUnitAbilityLevel(target,perktype)))
            call SetUnitAbilityLevel(target,perktype,GetUnitAbilityLevel(target,perktype)-1)
            call BJDebugMsg(I2S(GetUnitAbilityLevel(target,perktype)))
        else
            call UnitRemoveAbility(target,perktype)
        endif
        
        if UnitPerkCount[ID] == 1 then
            set UnitPerkCount[ID] = 0
            set UnitPerkPointer[ID] = -1
        else
            //Pointing next and previous perk to eachother
            set UnitPerkPrev[UnitPerkNext[index]] = UnitPerkPrev[index]
            set UnitPerkNext[UnitPerkPrev[index]] = UnitPerkNext[index]
            
            set UnitPerkCount[ID] = UnitPerkCount[ID] - 1
            set UnitPerkPointer[ID] = UnitPerkNext[index]
        endif
        
        set UnDexes = UnDexes + 1
        set UnDex[UnDexes] = index
        
        set UnitPerkType[index] = -1
    endfunction
    
    private function in takes nothing returns nothing
        set UnDexes = 1
        loop            
            set UnDex[UnDexes] = 8191-UnDexes
            
            exitwhen UnDexes == 8190
            set UnDexes = UnDexes + 1
        endloop
    endfunction
endlibrary


  • Unit Indexer
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: call ExecuteFunc("InitializeUnitIndexer")
      • Custom script: endfunction
      • -------- --------
      • -------- This is the most important function - it provides an index for units as they enter the map --------
      • -------- --------
      • Custom script: function IndexUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • -------- --------
      • -------- You can use the boolean UnitIndexerEnabled to protect some of your undesirable units from being indexed --------
      • -------- - Example: --------
      • -------- - Set UnitIndexerEnabled = False --------
      • -------- - Unit - Create 1 Dummy for (Triggering player) at TempLoc facing 0.00 degrees --------
      • -------- - Set UnitIndexerEnabled = True --------
      • -------- --------
      • -------- You can customize the following block - if conditions are false the (Matching unit) won't be indexed. --------
      • -------- --------
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • UnitIndexerEnabled Equal to (==) True
          • Then - Actions
            • -------- --------
            • -------- Generate a unique integer index for this unit --------
            • -------- --------
              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • UDexRecycle Equal to (==) 0
                • Then - Actions
                  • Set UDex = (UDexGen + 1)
                  • Set UDexGen = UDex
                • Else - Actions
                  • Set UDex = UDexRecycle
                  • Set UDexRecycle = UDexNext[UDex]
            • -------- --------
            • -------- Link index to unit, unit to index --------
            • -------- --------
            • Set UDexUnits[UDex] = (Matching unit)
            • Unit - Set the custom value of UDexUnits[UDex] to UDex
            • -------- --------
            • -------- Use a doubly-linked list to store all active indexes --------
            • -------- --------
            • Set UDexPrev[UDexNext[0]] = UDex
            • Set UDexNext[UDex] = UDexNext[0]
            • Set UDexNext[0] = UDex
            • -------- --------
            • -------- Fire index event for UDex --------
            • -------- --------
            • Set UnitIndexEvent = 0.00
            • Set UnitIndexEvent = 1.00
            • Set UnitIndexEvent = 0.00
            • Custom script: set udg_UDex = pdex
          • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • -------- --------
      • -------- The next function is called each time a unit enters the map --------
      • -------- --------
      • Custom script: function IndexNewUnit takes nothing returns boolean
      • Custom script: local integer pdex = udg_UDex
      • Custom script: local integer ndex
      • -------- --------
      • -------- Recycle indices of units no longer in-play every (15) units created --------
      • -------- --------
      • Set UDexWasted = (UDexWasted + 1)
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • UDexWasted Equal to (==) 15
          • Then - Actions
            • Set UDexWasted = 0
            • Set UDex = UDexNext[0]
            • Custom script: loop
            • Custom script: exitwhen udg_UDex == 0
              • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Custom value of UDexUnits[UDex]) Equal to (==) 0
                • Then - Actions
                  • -------- --------
                  • -------- Remove index from linked list --------
                  • -------- --------
                  • Custom script: set ndex = udg_UDexNext[udg_UDex]
                  • Custom script: set udg_UDexNext[udg_UDexPrev[udg_UDex]] = ndex
                  • Custom script: set udg_UDexPrev[ndex] = udg_UDexPrev[udg_UDex]
                  • Set UDexPrev[UDex] = 0
                  • -------- --------
                  • -------- Fire deindex event for UDex --------
                  • -------- --------
                  • Set UnitIndexEvent = 2.00
                  • Set UnitIndexEvent = 0.00
                  • -------- --------
                  • -------- Recycle the index for later use --------
                  • -------- --------
                  • Set UDexUnits[UDex] = No unit
                  • Set UDexNext[UDex] = UDexRecycle
                  • Set UDexRecycle = UDex
                  • Custom script: set udg_UDex = ndex
                • Else - Actions
                  • Set UDex = UDexNext[UDex]
            • Custom script: endloop
            • Custom script: set udg_UDex = pdex
          • Else - Actions
      • -------- --------
      • -------- Handle the entering unit (Matching unit) --------
      • -------- --------
        • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • (Custom value of (Matching unit)) Equal to (==) 0
          • Then - Actions
            • Custom script: call IndexUnit()
          • Else - Actions
      • Custom script: return false
      • Custom script: endfunction
      • -------- --------
      • -------- The next function initializes the core of the system --------
      • -------- --------
      • Custom script: function InitializeUnitIndexer takes nothing returns nothing
      • Custom script: local integer i = 0
      • Custom script: local region re = CreateRegion()
      • Custom script: local rect r = GetWorldBounds()
      • Set UnitIndexerEnabled = True
      • Custom script: call RegionAddRect(re, r)
      • Custom script: call TriggerRegisterEnterRegion(CreateTrigger(), re, Filter(function IndexNewUnit))
      • Custom script: call RemoveRect(r)
      • Custom script: set re = null
      • Custom script: set r = null
      • Custom script: loop
      • Custom script: call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, Player(i), Filter(function IndexUnit))
      • Custom script: set i = i + 1
      • Custom script: exitwhen i == 16
      • Custom script: endloop
      • -------- --------
      • -------- This is the "Unit Indexer Initialized" event, use it instead of "Map Initialization" for best results --------
      • -------- --------
      • Set UnitIndexEvent = 3.00
      • Set UnitIndexEvent = 0.00



JASS:
// import "StatManager.j"
// import "BonusAbils.j"
library InnerFire initializer in requires UnitPerk
    globals
        private integer array Arm
        private integer array UnitID
        private unit array Unit
        
        private constant integer PerkID = 'AInF'
    endglobals
    
    function InnerFireCreate takes unit target,unit owner,integer armor returns integer
        local integer index = InitPerk(PerkID,target,owner)
        set Unit[index] = target
        set UnitID[index] = GetUnitUserData(target)
        //call AddUnitArm(target,UnitID[index],armor)
        call UnitDamageTarget(owner, target, armor, false, true, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
        set Arm[index] = armor
        return index
    endfunction
    
    private function Destroy takes nothing returns boolean
        //call AddUnitArm(Unit[ToDestroy],UnitID[ToDestroy],-Arm[ToDestroy])
        call SetWidgetLife(Unit[ToDestroy], GetWidgetLife(Unit[ToDestroy]) + Arm[ToDestroy])
        call ClearPerk(ToDestroy)
        return false
    endfunction
    
    private function in takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerAddCondition(t,Condition(function Destroy))
        call SaveTriggerHandle(PerkTable,PerkID,PERK_DESTROY,t)
    endfunction
endlibrary

  • Inner Fire Gesture
    • Events
      • Unit - A unit Is issued an order targeting an object
    • Conditions
      • (Triggering unit) Equal to (==) Cleric 0001 <gen>
    • Actions
      • Multiple FunctionsIf (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Level of Inner Fire (+1) for (Target unit of issued order)) Less than (<) 10
        • Then - Actions
          • Custom script: call InnerFireCreate(GetOrderTargetUnit(),GetTriggerUnit(),3)
        • Else - Actions
JASS:
function Trig_Disenchant_Gesture_Actions takes nothing returns nothing
    local integer ID
    if GetTriggerUnit() == gg_unit_o000_0018 then
        set ID = GetUnitUserData(GetOrderTargetUnit())
        if UnitPerkPointer[ID] != -1 then
            call DestroyPerk(UnitPerkPointer[ID])
        endif
    endif
endfunction

//===========================================================================
function InitTrig_Disenchant_Gesture takes nothing returns nothing
    set gg_trg_Disenchant_Gesture = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Disenchant_Gesture, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
    call TriggerAddAction( gg_trg_Disenchant_Gesture, function Trig_Disenchant_Gesture_Actions )
endfunction

 
Last edited:

Deleted member 219079

D

Deleted member 219079

Wait, can you add buffs to units like abilities? Didn't know that, I thought you always had to use dummy caster to apply the buff onto unit.
 
Level 7
Joined
Oct 11, 2008
Messages
304
Actually, you can't add buffs as abilities, what the system do is adding a fake ability, it's based on something that I didn't remember (closed editor) and has 10 level (so, the buff stack 10 times), the ability itself just add a effect to the unit affected :p
 

Deleted member 219079

D

Deleted member 219079

What is "import statmanager"?

If that's some cJass import thing, just so you know I'm using vanilla vJass.
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
I think you can find all the imports here http://www.hiveworkshop.com/forums/pastebin.php?id=6v6ru0

Essentially what the system does is:
Gives a unit an ability, if such an ability exists. If it doesn't then you can't use the part of the system that makes similar buffs stack(by default).
However, you don't actually need the ability if you code a different way to handle stacking buffs.
Each buff has a virtual index that doesn't change throughout the game, so it can be indexed in an array.
Each unit has an ordered list of buffs that are in the order they were added in.
Each buff type registers a create and destroy function, which take their parameters as globals, because I can't otherwise call functions dynamically.(Create functions actually don't, but they should)
The destroy function is essential for things like purging, because it allows you to take any buff(by its array index) and tell it do disappear.

Inner fire shows how to define buffs.
Inner fire gesture tells how to apply them.
Disenchant gesture shows how to clear them.
 
Status
Not open for further replies.
Top