• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Orb Stacking 1.8.1

  • Like
Reactions: JesusHipster
A library to ease stacking orbs. And to add limitations to stacking orbs.

This uses vJass, DamageEvent, DamageModifiers, AutoIndex, Table and optionally GroupUtils.

-reset: Spawns some footmen around you.
-level <level>: Sets the level of your hero to the specified level. Note that you cannot decrease your hero's level this way.
-handleid: Creates a location, displays its index - 0x1000001 and destroys it.
-commands: Shows this list.
-credits: Shows the credits.
-clear: Clears all text-messages.


13/04/2009 - Version 1.0.0
- initial release

13/04/2009 - Version 1.0.1
- made removing the buff optional and moved it to the top to prevent recursion

16/04/2009 - Version 1.1.0
- changed internal handling of Item Orbs to Table for a performance gain
- each Orb now has a chance to be run. Refer to the manual for more information

16/04/2009 - Version 1.2.0
- added Category Types (if you have a more logical naming for those types, let me know)
- as a result of that, .AddToCategory()'s interface was changed.

23/04/2009 - Version 1.3.0
- each Category now has an execution limit, which can be adjusted
- backwards compatible

29/04/2009 - Version 1.3.1
- forgot to initialize the string table in the Category struct
- deleted irritating debug messages

29/04/2009 - Version 1.4.0
- reworked the way randomness is handled. 1.4.0 uses Ammorth's ChanceToProc library for that. Due to the severe performance impact i decided to keep 1.3.1 for those who are comfortable with the "spikes" the old way imposes on the chances

08/05/2009 - Version 1.5.0
- reworked the way randomness is handled (again). Removed the chance calculation on my side. The user decides whether the orb was applied or not with his own calculations
- as a result, the function interface was changed. You now have to return a boolean. For compatibility, use the constants provided by this library

22/05/2009 - Version 1.5.1
- deleted the superfluous H2I function
- minor other changes.

07/08/2009 - Version 1.5.2
- Compatibility with 1.24

06/11/2009 - Version 1.5.3
- fixed a few bugs by changing the ability the Generic Orb is based upon.
- Simplified implementation of the library and added a note that you have to add an ability to all units you want to have custom orbs.

06/02/2010 - Version 1.6.0
- Heavily optimized code run when a unit takes damage
- Made LightLeaklessDamageDetect exchangeable with IDDS by implementing an abstraction layer.

10/02/2010 - Version 1.6.1
- dramatically simplified importing this library. Now, you only need to copy over the code, everything else gets done automatically.
- removed the requirement of LightLeaklessDamageDetect, you can still use it, but its not required anymore.
- fixed Orbs for preplaced units.
- fixed destroying Orbs.
- clarified a few things in the documentation.

14/02/2010 - Version 1.6.2
- more bugfixes. Skilling the same ability multiple times no longer creates multiple UnitOrb instances.
- now supports adding Orbs via GUI.

15/02/2010 - Version 1.7.0
- breaks backwards compatibility in order to implement stacking priority. Orbs with higher priority get executed first. Only the interface of Orb.Create was changed.
- Allows changing the damage dealt to the damaged unit with the SetDamage(real new) function.

21/05/2010 - Version 1.8.0
- breaks backwards compatibility again. Ill get into that separately as basically the whole API changed. My aim was to reduce possibility of collision of names (eg. Category was far too general a name for a struct in a public library) (and i wanted to correct past mistakes).
- added missile modificators. Orbs can now change the missile a unit attacks with. Note that it doesnt take the target unit of an attack into account for speed reasons.

New API:
ABILITY_TYPE_SKILL --> ORB_TYPE_SKILL
ABILITY_TYPE_ITEM --> ORB_TYPE_ITEM
CATEGORY_TYPE_READ --> ORB_CATEGORY_TYPE_READ
CATEGORY_TYPE_WRITE --> ORB_CATEGORY_TYPE_WRITE
CATEGORY_TYPE_READWRITE --> ORB_CATEGORY_TYPE_READWRITE
Category --> OrbCategory
Orb_Callback --> OrbCallback
All members of publicly available structs now start with a lower-case-letter.

15/06/2010 - Version 1.8.1
- fixed OrbStacking for unit upgrading.
- did a few optimizations.
- added a few lines warning about using other orbs combined with this library (it just wont work the way you want it to).


JASS:
// *************************************************************
// *               OrbStacking -- Version 1.8.1
// *                        by Deaod
// *************************************************************
// *
// *    CREDITS:
// *        - Anitarf (DamageEvent, DamageModifiers)
// *        - grim001 (AutoIndex)
// *        - Rising_Dusk (GroupUtils)
// *        - Vexorian (JassHelper, Table)
// *        - MindWorX and PitzerMike (JassNewGenPack)
// *        - Pipedream (Grimoire)
// *        - SFilip (TESH)
// *
// *    HOW TO IMPORT:
// *        * Copy over this library and save. Its that easy.
// *
// *    HOW TO USE:
// *        * use Orb.create(integer AID, integer Method, integer Priority, OrbCallback Func)
// *          to create a new Orb.
// *            - AID is the ID of the ability representing the orb
// *              (in the case of an item representing the orb, pass
// *              the rawcode of the item)
// *            - Method is the type of ability triggerin the orb
// *              (either ORB_TYPE_SKILL, if the ability is a
// *              skill, or ORB_TYPE_ITEM, if an item triggers
// *              the orb)
// *            - Priority is the priority of the orb. When stacking
// *              different orbs on the same unit, the orb with the
// *              highest priority will get executed first.
// *              If a unit has two orbs of equal priority, the one
// *              acquired first will be executed first.
// *            - Func is the function being run when the orb is
// *              triggered. It has to follow the OrbCallback
// *              interface defined below. A function following that
// *              interface has to return a boolean, either
// *              ORB_APPLIED or ORB_NOT_APPLIED.
// *              If you return ORB_APPLIED, all Categories of type
// *              WRITE will be written (their execution-count will
// *              be increased)
// *
// *        * add that Orb to a category using YourOrb.addToCategory(string Label, integer Type)
// *            - Label is the label of the category you want to
// *              add that orb to.
// *              Every Orb can belong to up to MAX_CATEGORIES
// *              categories
// *            - Type defines the behaviour of the orb.
// *              ORB_CATEGORY_TYPE_READ makes the orb only "read" from
// *              the Category. That means it only checks whether
// *              that category has been written in any orb before.
// *              ORB_CATEGORY_TYPE_WRITE makes the orb only "write" to
// *              the Category. That means it only marks the Category
// *              as executed but does not depend on the Category not
// *              being executed before.
// *              ORB_CATEGORY_TYPE_READWRITE combines READ and WRITE.
// *              That means, the orb will not be executed, if the
// *              Category has been executed before and it will mark
// *              the Category as executed when the orb is triggered
// *
// *        * each Category has an execution limit and cant be executed
// *          more often than that limit. You can change that limit
// *          using this: set OrbCategory[label].execLimit=some_new_limit
// *            - label is the label of the Category which's execution
// *              limit you want to change
// *
// *        * you can add a missile modifier to each Orb by using
// *          YourOrb.setMissileModifier(integer Ability)
// *            - Ability is the rawcode of an ability that places BID
// *              on the attacked unit and modifies the missile.
// *              You should base this ability off of AIcb for optimum
// *              performance.
// *          If a unit has an orb with a missile modifier, that
// *          modifier gets used. If the unit has more than one, the
// *          one of the orb with highest priority gets used.
// *          Missile modifiers currently dont get added to units already
// *          having the ability/item for the orb when the orb is created
// *          in the code. Though i dont think this will ever be an issue
// *          please tell me if you run into a situation where it is.
// *          Note that you wont be able to change the missile if the
// *          dummy ability isnt able to change the missile under the
// *          given circumstances.
// *
// *        * GetDamagingUnit(), GetDamagedUnit() and GetDamage() can be
// *          used to access GetEventDamageSource(), GetTriggerUnit()
// *          and GetEventDamage() inside OrbCallback functions
// *          executed by this script
// *
// *        * if you want to prevent damage or deal additional damage
// *          through orbs, use the SetDamage(real new) function.
// *          Pass the new amount of damage that attack should deal.
// *          Using it outside Orb Callbacks wont have any effect.
// *
// *        * by default, all units that get indexed by AutoIndex upon
// *          entering the map, automatically get the dummy ability for
// *          OrbStacking. If there are specific types you want to
// *          exclude from acquiring orbs, filter them out using the
// *          UnitFilter function right below the first globals block.
// *          If you add the dummy ability to a unit, that unit wont
// *          be able to use other orbs anymore. They also should not
// *          be able to attack ground as that can cause crashes.
// *
// *************************************************************
library OrbStacking uses Table, DamageEvent, DamageModifiers, AutoIndex, optional GroupUtils
   
    // these are the objects required for this library to function
    // you can deactivate these after saving and immediately reopening the map (by removing the ! or adding a / in the front).
    //! external ObjectMerger w3a AIcb AOrb anam "Generic Orb" aart "" arac "0" amat "" asat "" aspt "" atat "" ata0 ""  Iarp 1 0 Idic 1 0 Iob5 1 0 abuf 1 "BORB" ahdu 1 "0.01" adur 1 "0.01" aite "0"
    //! external ObjectMerger w3h Bfro BORB fnam "Proxy Orb" ftat "" ftip "Proxy Orb" fube ""
   
    globals
                constant    key                         ORB_TYPE_SKILL              //
                constant    key                         ORB_TYPE_ITEM               //
               
                constant    key                         ORB_CATEGORY_TYPE_READ      // categories of this type for the orb must not have been written before
                constant    key                         ORB_CATEGORY_TYPE_WRITE     // whenever an orb belonging to this type of category is triggered that category becomes unusable
                constant    key                         ORB_CATEGORY_TYPE_READWRITE // combines READ and WRITE
               
                constant    boolean                     ORB_APPLIED                 = true
                constant    boolean                     ORB_NOT_APPLIED             = false
               
        private constant    integer                     AID                         = 'AOrb' // Based off of AIcb, places BID on attacked unit.
        private constant    integer                     BID                         = 'BORB' // the buff placed by the dummy orb ability // based on Orb of Corruption
        private constant    integer                     MAX_CATEGORIES              = 5 // the maximum categories an orb can belong to
        private constant    integer                     DEFAULT_CATEGORY_EXEC_LIMIT = 1 // the default execution limit of a newly created OrbCategory
        private constant    boolean                     REMOVE_BUFF_BEFORE          = true // change to false, if you need the buff in one of your callbacks
        private constant    integer                     ORB_PRIORITY                = 0x7FFFFFFF // highest possible value, meaning all orbs will get executed before any other damage modifiers get a chance
    endglobals
   
    // If theres any specific unit-type you want to exclude from using Orbs at all, filter it out here.
    // Note that AutoIndex already filters out xe's dummies, and that units not indexed by AutoIndex wont be able to use Orbs
    private function UnitFilter takes unit u returns boolean
        return true
    endfunction
   
    // Dont touch it, its just here for you to see
    function interface OrbCallback takes nothing returns boolean
   
    // Dont touch anything below.
   
    globals
        private unit Damaging
        private unit Damaged
        private real Damage
    endglobals
   
    struct OrbCategory
        private integer execlimit
       
        private static StringTable CategoryTable
       
        method operator execLimit takes nothing returns integer
            return execlimit
        endmethod
       
        method operator execLimit= takes integer new returns nothing
            debug if new<=0 then
            debug     call BJDebugMsg("OrbCategory: New execution limit too low!")
            debug     return
            debug endif
            set execlimit=new
        endmethod
       
        private static method Create takes string label returns thistype
        local thistype s=allocate()
            set s.execLimit=DEFAULT_CATEGORY_EXEC_LIMIT
            set CategoryTable[label]=s
            return s
        endmethod
       
        static method create takes string label returns thistype
            if CategoryTable.exists(label) then
                return CategoryTable[label]
            else
                return Create(label)
            endif
        endmethod
       
        static method operator [] takes string label returns thistype // a cleaner wrapper
            return create(label)
        endmethod
       
        private method destroy takes nothing returns nothing
            // i hope this prevents idiots from destroying a Category
        endmethod
       
        private static method onInit takes nothing returns nothing
            set OrbCategory.CategoryTable=StringTable.create()
        endmethod
    endstruct
   
    private keyword UnitOrb
    // the following are terrible hacks to create library-private struct members
    private keyword aid
    private keyword Method
    private keyword Cat
    private keyword CatType
    private keyword CatCnt
    private keyword cb
    private keyword Priority
    private keyword MissileModAbil
   
    private struct OrbUnit extends DamageModifier
        private unit self
        private integer id
        readonly UnitOrb missileMod
       
        private static integer array OrbCount
        private static thistype array UnitInstance
       
        method destroy takes nothing returns nothing
            set OrbCount[id]=OrbCount[id]-1
            if OrbCount[id]==0 then
                set self=null
                set UnitInstance[id]=0
                call deallocate()
            endif
        endmethod
       
        method newMissileMod takes UnitOrb newmod returns nothing
            call UnitRemoveAbility(self, missileMod.orb.MissileModAbil)
            call UnitAddAbility(self, newmod.orb.MissileModAbil)
            set missileMod=newmod
        endmethod
       
        method resetMissileMod takes nothing returns nothing
            call UnitRemoveAbility(self, missileMod.orb.MissileModAbil)
            call UnitAddAbility(self, AID)
            set missileMod=UnitOrb[self]
        endmethod
       
        private method onDamageDealt takes unit target, real damage returns real
        local integer i
        local Orb s
        local integer array b // counts the execution of each category
        local boolean t
        local UnitOrb o
            if GetUnitAbilityLevel(target, BID)<=0 then
                // not triggered by an attack.
                return 0.
            endif
            static if REMOVE_BUFF_BEFORE then
                call UnitRemoveAbility(target, BID)
            endif
            set Damaging=self
            set Damaged=target
            set Damage=damage
            set o=UnitOrb[self]
            loop
                exitwhen o==0
                set s=o.orb
                set i=0
                set t=true
                loop
                    exitwhen i>=s.CatCnt
                    // lets see if were allowed to trigger the Orb
                    if (s.CatType[I]==ORB_CATEGORY_TYPE_READ or s.CatType[I]==ORB_CATEGORY_TYPE_READWRITE) and b[s.Cat[I]]>=s.Cat[I].execLimit then
                        set t=false // we arent
                        exitwhen true
                    endif
                    set i=i+1
                endloop
                if t and s.cb.evaluate()==ORB_APPLIED then // additionally check if the Orb actually triggered (for chance based Orbs)
                    set i=0
                    loop
                        exitwhen i>=s.CatCnt
                        // now, lets mark the categories as execute once more
                        if s.CatType[I]==ORB_CATEGORY_TYPE_WRITE or s.CatType[I]==ORB_CATEGORY_TYPE_READWRITE then
                            set b[s.Cat[I]]=b[s.Cat[I]]+1
                        endif
                        set i=i+1
                    endloop
                endif
                set o=o[o.index+1] // and loop through the Orbs of the unit
            endloop
            return Damage-damage // return newdamage-olddamage
        endmethod
        
        static method create takes unit u returns thistype
        local integer id=GetUnitId(u)
            if UnitInstance[id]==0 then
                set UnitInstance[id]=allocate(u, ORB_PRIORITY)
                set UnitInstance[id].id=id
                set UnitInstance[id].self=u
                set UnitInstance[id].missileMod=AID
            endif
            set OrbCount[id]=OrbCount[id]+1
            return UnitInstance[id]
        endmethod
    endstruct
    
    private struct UnitOrb
        Orb orb
        OrbUnit orbunit
        
        implement AutoDestroy
        
        static method clear takes unit u returns nothing
        local thistype o
        local thistype p
            set o=UnitOrb[/I][/I][/I][/I][/I][/I][/I][/I]
            loop
                exitwhen o==0
                set p=o[o.index+1]
                call o.destroy()
                set o=p
            endloop
        endmethod
        
        private method onDestroy takes nothing returns nothing
        local thistype o
            if orbunit.missileMod==this then
                set o=o[o.index+1] // start with the next orb in line
                loop
                    exitwhen o==0
                    if o.orb.MissileModAbil!=AID then
                        call o.orbunit.newMissileMod(o)
                    endif
                    set o=o[o.index+1]
                endloop
                if o.orbunit.missileMod==this then
                    call o.orbunit.resetMissileMod()
                endif
            endif
            call orbunit.destroy()
        endmethod
        
        static method create takes unit u, Orb orb returns thistype
            local thistype s=allocate()
            local thistype o
            local boolean b // theres a missile modifier with higher priority or the orb does not have a missile modifier.
            set s.orb=orb
            set s.orbunit=OrbUnit.create(u)
            set o=UnitOrb
            set b=s.orb.MissileModAbil==AID
            // search the right place to insert
            loop
                exitwhen o==0 or o.orb.Priority<orb.Priority
                if not b and o.orb.MissileModAbil!=AID then
                    set b=true
                endif
                set o=o[o.index+1]
            endloop
            set s.me=u // insert at end
            if not b then
                // apply new Missile Modifier
                call s.orbunit.newMissileMod(s)
            endif
            loop // shift instances moving new instance to the right place
                exitwhen o==0
                set o.me=u
                set o=o[o.index+1]
            endloop
            return s
        endmethod
    endstruct
    
    struct Orb
        integer aid
        integer Method
        OrbCategory array Cat[MAX_CATEGORIES]
        integer array CatType[MAX_CATEGORIES]
        integer CatCnt=0
        OrbCallback cb
        integer Priority=0
        integer MissileModAbil=AID
        
        private integer i
        
        private static thistype array Structs
        private static integer Count=0
        
        private static Table OrbTable
        
        private static rect WorldRect
        private static group InitGroup
        private static thistype TempOrb
        
        private static method OnDestroyCheck takes nothing returns boolean
        local UnitOrb o
        local UnitOrb next
            
            set o=UnitOrb[GetFilterUnit()]
            loop
                exitwhen o<=0
                if o.orb==TempOrb then
                    set next=o[o.index+1]
                    call o.destroy()
                    set o=next
                else
                    set o=o[o.index+1]
                endif
            endloop
            
            return false
        endmethod
        
        method onDestroy takes nothing returns nothing
            set TempOrb=this
            static if LIBRARY_GroupUtils then
                call GroupEnumUnitsInRect(ENUM_GROUP, WorldRect, function thistype.OnDestroyCheck)
            else
                call GroupEnumUnitsInRect(InitGroup, WorldRect, function thistype.OnDestroyCheck)
            endif
            if Method==ORB_TYPE_SKILL then
                set Count=Count-1
                set Structs=Structs[Count]
                set Structs.i=i
            endif
            call OrbTable.flush(.aid)
        endmethod
        
        private static method OnCreateCheck takes nothing returns boolean
        local unit u=GetFilterUnit()
            if UnitFilter(u) then
                if TempOrb.Method==ORB_TYPE_SKILL and GetUnitAbilityLevel(u, TempOrb.aid)>0 then
                    call UnitOrb.create(u, TempOrb)
                elseif TempOrb.Method==ORB_TYPE_ITEM and UnitHasItemOfTypeBJ(u, TempOrb.aid) then
                    call UnitOrb.create(u, TempOrb)
                endif
            endif
            set u=null
            return false
        endmethod
        
        static method create takes integer AID, integer Method, integer Priority, OrbCallback Func returns Orb
        local thistype s=allocate()
            set s.aid=AID
            set s.cb=Func
            if Method==ORB_TYPE_SKILL then
                set Structs[Count]=s
                set s.i=Count
                set Count=Count+1
            endif
            set s.Method=Method
            set s.Priority=Priority
            set OrbTable[AID]=s
            set TempOrb=s
            static if LIBRARY_GroupUtils then
                call GroupEnumUnitsInRect(ENUM_GROUP, WorldRect, function thistype.OnCreateCheck)
            else
                call GroupEnumUnitsInRect(InitGroup, WorldRect, function thistype.OnCreateCheck)
            endif
            return s
        endmethod
        
        method addToCategory takes string Label, integer Type returns nothing
            debug if CatCnt>=MAX_CATEGORIES or Label=="" or Label==null or (Type!=ORB_CATEGORY_TYPE_READ and Type!=ORB_CATEGORY_TYPE_WRITE and Type!=ORB_CATEGORY_TYPE_READWRITE) then
            debug     call BJDebugMsg("OrbStacking: Can't add Orb["+I2S(this)+"] to another OrbCategory (wrong label, invalid type, or maximum categories exceeded)!")
            debug     return 
            debug endif
            set Cat[CatCnt]=OrbCategory.create(Label)
            set CatType[CatCnt]=Type
            set CatCnt=CatCnt+1
        endmethod
        
        method setMissileModifier takes integer Ability returns nothing
            set MissileModAbil=Ability
        endmethod
        
        private static method UnitCreated takes unit u returns nothing
        local integer i=Orb.Count-1
        local thistype s
            if UnitFilter(u) then
                call UnitAddAbility(u, AID)
                
                loop
                    exitwhen i<0
                    set s=Structs
                    if GetUnitAbilityLevel(u, s.aid)>0 then
                        call UnitOrb.create(u, s)
                    endif
                    set i=i-1
                endloop
            endif
        endmethod
        
        private static method OnUpgrade takes nothing returns nothing
        local unit u=GetTriggerUnit()
            call UnitOrb.clear(u)
            call UnitCreated(u)
            set u=null
        endmethod
        
        private static method OnSkill takes nothing returns nothing
        local thistype s=OrbTable[GetLearnedSkill()]
        local UnitOrb o
            if UnitFilter(GetTriggerUnit()) and s>0 and GetLearnedSkillLevel()==1 then
                set o=UnitOrb.create(GetTriggerUnit(), s)
            endif
        endmethod
        
        private static method OnItemPickup takes nothing returns nothing
        local thistype s=OrbTable[GetItemTypeId(GetManipulatedItem())]
        local UnitOrb o
            if UnitFilter(GetTriggerUnit()) and s>0 then
                set o=UnitOrb.create(GetTriggerUnit(), s)
            endif
        endmethod
        
        private static method OnItemDrop takes nothing returns nothing
        local thistype s=OrbTable[GetItemTypeId(GetManipulatedItem())]
        local UnitOrb o
            if s>0 then
                set o=UnitOrb[GetTriggerUnit()]
                loop
                    exitwhen o<=0
                    if o.orb==s then
                        call o.destroy()
                        return
                    endif
                    set o=o[o.index+1]
                endloop
            endif
        endmethod
        
        private static method OnUnitAddAbility takes unit u, integer aid returns nothing
        local thistype s=OrbTable[aid]
        local UnitOrb o
            if UnitFilter(u) and s>0 and GetUnitAbilityLevel(u, aid)<=0 then
                set o=UnitOrb.create(u, s)
            endif
        endmethod
        
        private static method OnUnitAddAbilityBJ takes integer aid, unit u returns nothing
            call OnUnitAddAbility(u, aid)
        endmethod
        
        private static method OnUnitRemoveAbility takes unit u, integer aid returns nothing
        local thistype s=OrbTable[aid]
        local UnitOrb o
            if s>0 and GetUnitAbilityLevel(u, aid)>0 then
                set o=UnitOrb
                loop
                    exitwhen o<=0
                    if o.orb==s then
                        call o.destroy()
                        return
                    endif
                    set o=o[o.index+1]
                endloop
            endif
        endmethod
        
        private static method OnUnitRemoveAbilityBJ takes integer aid, unit u returns nothing
            call OnUnitRemoveAbility(u, aid)
        endmethod
        
        private static method onInit takes nothing returns nothing
        local trigger t
            // Listener for units entering the map
            call OnUnitIndexed(UnitCreated)
            // Listener for upgrading a unit
            set t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_UPGRADE_FINISH)
            call TriggerAddAction(t, function thistype.OnUpgrade)
            // Listener for learning an ability
            set t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_HERO_SKILL)
            call TriggerAddAction(t, function thistype.OnSkill)
            // Listener for picking up and item
            set t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_PICKUP_ITEM)
            call TriggerAddAction(t, function thistype.OnItemPickup)
            // Listener for dropping an item
            set t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DROP_ITEM)
            call TriggerAddAction(t, function thistype.OnItemDrop)
            
            set OrbTable=Table.create()
            
            set WorldRect=GetWorldBounds() // sadly, you cant initialize rects using this function inside the globals block, unless you want the game to crash
            static if not LIBRARY_GroupUtils then
                set InitGroup=CreateGroup() // only initialize if necessary.
            endif
        endmethod
    endstruct
    
    hook UnitAddAbility         Orb.OnUnitAddAbility
    hook UnitAddAbilityBJ       Orb.OnUnitAddAbilityBJ
    hook UnitRemoveAbility      Orb.OnUnitRemoveAbility
    hook UnitRemoveAbilityBJ    Orb.OnUnitRemoveAbilityBJ
    hook UnitRemoveBuffBJ       Orb.OnUnitRemoveAbilityBJ
    
    function GetDamagingUnit takes nothing returns unit
        return Damaging
    endfunction
    
    function GetDamagedUnit takes nothing returns unit
        return Damaged
    endfunction
    
    function GetDamage takes nothing returns real
        return Damage
    endfunction
    
    function SetDamage takes real new returns nothing
        set Damage=new
    endfunction
    
endlibrary

I additionally attached a map with two samples.
Contents

Orb Stacking 1.8.0 (Map)

Reviews
20:56, 4th Jun 2009 hvo-busterkomo: It's well scripted, and definitely useful. The screenshot seems fine to me- after all, visual effects are hardly the aim of systems.

Moderator

M

Moderator

20:56, 4th Jun 2009
hvo-busterkomo:
It's well scripted, and definitely useful. The screenshot seems fine to me- after all, visual effects are hardly the aim of systems.
 
Level 14
Joined
Nov 18, 2007
Messages
816
@DSG: you DO realize i cant capture an Orb Stacking library with a screenshot easily? I find it more descriptive to use the current screenshot (although, if you insist, i can change the image to one displaying this library in action).
 
Level 14
Joined
Nov 18, 2007
Messages
816
Orbs are effects that trigger (or have a chance to trigger) every time a unit with an orb damages another unit. Life Steal granted by some item, armor reduction, mana burn (feedback, i think its called), those are all examples of orbs implemented by blizzard.
Heres where the stacking part comes in: Stacking all those different orbs on one unit is not possible. The unit would have 2 Orbs at most (playdota.com has a good reference for what orbs stack with one another by default). This library essentially allows you to stack an infinite amount of orbs on one unit. Though its necessary to recode every orb to use this library (even blizzards hardcoded orbs).
 
Level 14
Joined
Nov 18, 2007
Messages
816
Youre free to use IDDS inside your map. I should probably delete LLDD from the demo as its not a necessary requirement. But while IDDS does allow easy distinction between attacks and spells (at the cost of some effort, especially in already big maps), this library offers restriciting Orb stacking, which would be impossible with just responding to damage events. Its also more efficient to just execute the functions that need to be run, than executing every function whenever a unit takes damage to check if its an attack and then possibly execute the orb. This is meant to make stacking orbs easier.
 
Level 2
Joined
Aug 16, 2011
Messages
2
sorry but if in function Actions i call GetDamageingUnit damage GetDamaged unit some bonus damage less than GetDamage then WarIII do not identify that who damaged to GetDamaged unit...if you understand what I'm saying,please test and fix,sorry i'm low levels of english,thanks
 
Level 27
Joined
Feb 2, 2006
Messages
1,578
Hi, is this system still being maintained? Can you maybe describe/explain a bit how this system works internally? Do you create dummies damaging the target with the orb abilities? Or do you fake the abilities or do you fake multiple attacks? For me the example triggers look like you have to write the orb effects yourself? At least LifeSteal and ManaBurn look like that.

Does it support standard orb abilities stacking without any coding of the effects?

And can you maybe fix the code tags in the description?
 
Level 18
Joined
Oct 17, 2012
Messages
849
All orb effects are triggered in order to take advantage of its custom priority system. The triggered effects are then ran on a damage dealt event without using any dummies.

I wonder if using a dummy unit to attack would be better in terms of performance and behavior. I don't know if one dummy would suffice. I would have to disable and re-enable abilities and have the dummy unit attack multiple times. I don't see how one dummy could attach all orb effects to an enemy unit simultaneously.

Would one dummy unit per orb effect be better? I would have to change the owner of said dummy unit because one dummy unit per orb effect per player would be too many dummy units. I could use the fact that some orb effects stack to my advantage in order to reduce the number of dummy units required. Then there is the matter of missile effects...
 
Last edited:
Top