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

Drain System 1.02

  • Like
Reactions: deepstrasz and Ofel
It's a system that handles life/mana drain for you... It also has support for setting four different event responses to aid you in making a not-just-another-drain spell...

Note: these drains are basically, non-channeled... but you can still create channeled drains by either utilizing the event responses or linking the Drain instance (which is returned by the creation methods) to the unit and calling the remove method if the unit
is ordered anything... you could also try the IsChanneling snippet on the JASS sections...

System:
JASS:
/*
    Drain System v1.02
    by Adiktuz
    
    A system that handles draining abilities
    
    Features:
        ->Can have a simultaneous life and mana drain
        ->Can have different values for the drain and the damage dealt to the drained unit 
        ->Can set the attacktype and damagetype of the drain
        
    How to use: 
        
        ->Drain.methodName(parameters)
        
    Methods that can be used for drains
    
    life(unit u1, unit u2, real lifedrain, real duration, real breakpoint, string lfx, string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey)
    mana(unit u1, unit u2, real manadrain, real duration,real breakpoint,string lfx,  string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey)
    lifeMana(unit u1, unit u2, real lifedrain, real manadrain, real duration,real breakpoint,string lfx,  string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey)
    lifeEx(unit u1, unit u2, real lifedrain, real lifedamage, real duration, real breakpoint, string lfx, string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey)
    manaEx(unit u1, unit u2, real manadrain, real manadamage, real duration,real breakpoint,string lfx,  string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey)
    lifeManaEx(unit u1, unit u2, real lifedrain, real lifedamage, real manadrain, real manadamage, real duration,real breakpoint,string lfx,  string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey)
    
    Parameters:
    unit u1 -> the caster
    unit u2 -> the target
    real lifedrain -> the amount of life added to u1 per second
    real lifedamage -> the amount of life damage to u2 per second
    real manadrain -> the amount of mana added to u1 per second
    real manadamage -> the amount of mana damage to u2 per second
    real duration -> the maximum duration of the drain
    real breakpoint -> the maximum range of the drain
    string lfx -> the string path of the lightning effect 
    string e1 -> the special effect to be attached to u1 for the duration of the drain
    string e2 -> the special effect to be attached to u2 for the duration of the drain
    string apoint1 -> the attachment point of e1
    string apoint2 -> the attachment point of e2
    attacktype at -> the attack type of the life damage 
    damagetype dt -> the damage type of the life damage 
    
    Note: all of these methods return the instance of the drain so you can save it in a variable
    
    To forcibly stop a drain:
    
    remove(integer eventtype)
    
    integer eventtype -> determines if the drain is broken,ended or target died
                      -> if 1, it is broken
                      -> if 2, it ended
                      -> if 3, target died
                      -> use any other number if no event response should be run
    
    Extra/Interface/Events:
        
        registerUpdateEvent(integer eventkey, code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a drain with the
           same eventkey as the one registered is updated (every T32_PERIOD)
        
        registerEndEvent(integer eventkey, code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a drain with the
           same eventkey as the one registered ends (duration ends)
        
        registerBreakEvent(integer eventkey, code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a drain with the
           same eventkey as the one registered is broken (the breakpoint is reached)
           
        registerDeathEvent(integer eventkey, code ToDo) returns nothing
        -> allows you to register an action that will be run whenever target unit dies
        
        registerSelfDeathEvent(integer eventkey, code ToDo) returns nothing
        -> allows you to register an action that will be run whenever the casting unit dies
           
        NOTE: If you're going to use the next five functions/methods, make sure you set the
              corresponding boolean at the globals block to true
        
        registerGlobalUpdateEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a drain 
           is updated (every T32_PERIOD)
        
        registerGlobalEndEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a drain ends
        
        registerGlobalBreakEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a drain breaks
        
        registerGlobalDeathEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a drain target dies
        
        registerGlobalSelfDeathEvent(code ToDo) returns nothing
        -> allows you to register an action that will be run whenever a drain user dies
        
    To obtain the instance that run the events:
    
    getTriggeringDrain()
    
    See the example triggers for a better idea on how to use it
*/

library DrainSystem requires LightningSystem
    
    globals
        //Set to true if you're gonna use the global update event handler
        private constant boolean USE_GLOBAL_UPDATE = false 
        //Set to true if you're gonna use the global end event handler
        private constant boolean USE_GLOBAL_END = false 
        //Set to true if you're gonna use the global break event handler
        private constant boolean USE_GLOBAL_BREAK = false 
        //Set to true if you're gonna use the global death event handler
        private constant boolean USE_GLOBAL_DEATH = false 
        //Set to true if you're gonna use the global selfdeath event handler
        private constant boolean USE_GLOBAL_SELFDEATH = false 
        //hbase eight of lightning for normal units
        private constant real zbuffer = 50.0
        //base height of lightning for flying units
        //negative because flying units seem to have a default positive buffer for the lightning z
        private constant real flyzbuffer = -100.0
        private Table UpdateTable
        private Table EndTable
        private Table BreakTable
        private Table DeathTable
        private Table SelfDeathTable
        private trigger globalUpdate
        private trigger globalEnd
        private trigger globalBreak
        private trigger globalDeath
        private trigger globalSelfDeath
    endglobals
    
    private module init 
        static method onInit takes nothing returns nothing
            set UpdateTable = Table.create()
            set EndTable = Table.create()
            set BreakTable = Table.create()
            set DeathTable = Table.create()
            set SelfDeathTable = Table.create()
            static if USE_GLOBAL_UPDATE then
                set globalUpdate = CreateTrigger()
            endif
            static if USE_GLOBAL_END then
                set globalEnd = CreateTrigger()
            endif
            static if USE_GLOBAL_BREAK then
                set globalBreak = CreateTrigger()
            endif
            static if USE_GLOBAL_DEATH then
                set globalDeath = CreateTrigger()
            endif
            static if USE_GLOBAL_SELFDEATH then
                set globalSelfDeath = CreateTrigger()
            endif
        endmethod
    endmodule
    
    struct Drain extends array
        Lightning light
        unit u1
        unit u2
        real duration
        real lifedrain
        real manadrain
        real lifedamage
        real manadamage
        real breakpoint
        effect e1
        effect e2
        integer eventkey
        string apoint1
        string apoint2
        attacktype at
        damagetype dt
        boolean isLife
        boolean isMana
        static thistype instance
        private static integer instanceCount = 0
        private static thistype recycle = 0
        private thistype recycleNext
        
        static method registerSelfDeathEvent takes integer eventkey, code toDo returns nothing
            if not SelfDeathTable.handle.has(eventkey) then
                set SelfDeathTable.trigger[eventkey] = CreateTrigger()
            endif
            call TriggerAddCondition(SelfDeathTable.trigger[eventkey],Filter(toDo))
        endmethod
        
        static method registerDeathEvent takes integer eventkey, code toDo returns nothing
            if not DeathTable.handle.has(eventkey) then
                set DeathTable.trigger[eventkey] = CreateTrigger()
            endif
            call TriggerAddCondition(DeathTable.trigger[eventkey],Filter(toDo))
        endmethod
        
        static method registerEndEvent takes integer eventkey, code toDo returns nothing
            if not EndTable.handle.has(eventkey) then
                set EndTable.trigger[eventkey] = CreateTrigger()
            endif
            call TriggerAddCondition(EndTable.trigger[eventkey],Filter(toDo))
        endmethod
        
        static method registerBreakEvent takes integer eventkey, code toDo returns nothing
            if not BreakTable.handle.has(eventkey) then
                set BreakTable.trigger[eventkey] = CreateTrigger()
            endif
            call TriggerAddCondition(BreakTable.trigger[eventkey],Filter(toDo))
        endmethod
        
        static method registerUpdateEvent takes integer eventkey, code toDo returns nothing
            if not UpdateTable.handle.has(eventkey) then
                set UpdateTable.trigger[eventkey] = CreateTrigger()
            endif
            call TriggerAddCondition(UpdateTable.trigger[eventkey],Filter(toDo))
        endmethod
        
        static method registerGlobalEndEvent takes code toDo returns nothing
            call TriggerAddCondition(globalEnd,Filter(toDo))
        endmethod
        
        static method registerGlobalUpdateEvent takes code toDo returns nothing
            call TriggerAddCondition(globalUpdate,Filter(toDo))
        endmethod
        
        static method registerGlobalBreakEvent takes code toDo returns nothing
            call TriggerAddCondition(globalBreak,Filter(toDo))
        endmethod
        
        static method registerGlobalDeathEvent takes code toDo returns nothing
            call TriggerAddCondition(globalDeath,Filter(toDo))
        endmethod
        
        static method registerGlobalSelfDeathEvent takes code toDo returns nothing
            call TriggerAddCondition(globalSelfDeath,Filter(toDo))
        endmethod
        
        static method getZ takes unit u returns real
            if IsUnitType(u,UNIT_TYPE_FLYING) then
                return flyzbuffer
            endif
            return zbuffer
        endmethod
        
        static method getTriggeringDrain takes nothing returns thistype
            return instance
        endmethod
        
        method remove takes integer eventtype returns nothing
            call this.light.remove()
            call DestroyEffect(this.e1)
            call DestroyEffect(this.e2)
            set instance = this
            if eventtype == 1 then
                if BreakTable.handle.has(this.eventkey) then
                    call TriggerEvaluate(BreakTable.trigger[this.eventkey])
                endif
                static if USE_GLOBAL_BREAK then
                    call TriggerEvaluate(globalBreak)
                endif
            elseif eventtype == 2 then
                if EndTable.handle.has(this.eventkey) then
                    call TriggerEvaluate(EndTable.trigger[this.eventkey])
                endif
                static if USE_GLOBAL_END then
                    call TriggerEvaluate(globalEnd)
                endif
            elseif eventtype == 3 then
                if DeathTable.handle.has(this.eventkey) then
                    call TriggerEvaluate(DeathTable.trigger[this.eventkey])
                endif
                static if USE_GLOBAL_DEATH then
                    call TriggerEvaluate(globalDeath)
                endif
            elseif eventtype == 4 then
                if SelfDeathTable.handle.has(this.eventkey) then
                    call TriggerEvaluate(SelfDeathTable.trigger[this.eventkey])
                endif
                static if USE_GLOBAL_SELFDEATH then
                    call TriggerEvaluate(globalSelfDeath)
                endif
            endif
            call this.stopPeriodic()
            set .recycleNext=recycle
            set recycle=this
        endmethod
        
        static method new takes nothing returns thistype
            local thistype this = recycle
            if (this == 0) then
                set instanceCount = instanceCount + 1
                return instanceCount
            endif
                set recycle = recycle.recycleNext
            return this
        endmethod
        
        method periodic takes nothing returns nothing
            set this.duration = this.duration - T32_PERIOD
            set instance = this
            if UpdateTable.handle.has(this.eventkey) then
                call TriggerEvaluate(UpdateTable.trigger[this.eventkey])
            endif
            static if USE_GLOBAL_UPDATE then
                call TriggerEvaluate(globalUpdate)
            endif
            if this.isLife then
                call SetWidgetLife(this.u1,GetWidgetLife(this.u1) + this.lifedrain)
                call UnitDamageTarget(this.u1,this.u2,this.lifedamage,false,false,this.at,this.dt,null)
            endif
            if this.isMana then
                call SetUnitState(this.u1, UNIT_STATE_MANA, GetUnitState(this.u1,UNIT_STATE_MANA) + this.manadrain)
                call SetUnitState(this.u2, UNIT_STATE_MANA, GetUnitState(this.u2,UNIT_STATE_MANA) - this.manadamage)
            endif
            if this.duration <= 0.0 then
                call this.remove(2)
            elseif ((GetUnitX(this.u1) - GetUnitX(this.u2))*(GetUnitX(this.u1) - GetUnitX(this.u2)) + (GetUnitY(this.u1) - GetUnitY(this.u2))*(GetUnitY(this.u1) - GetUnitY(this.u2))) > this.breakpoint  then
                call this.remove(1)
            elseif GetWidgetLife(this.u2) < .405 or IsUnitType(this.u2,UNIT_TYPE_DEAD) then
                call this.remove(3)
            elseif GetWidgetLife(this.u1) < .405 or IsUnitType(this.u1,UNIT_TYPE_DEAD) then
                call this.remove(4)
            endif
        endmethod
        
        implement T32x
        
        static method life takes unit u1, unit u2, real lifedrain, real duration, real breakpoint, string lfx, string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey returns thistype
            local thistype this = thistype.new()
            set this.u1 = u1
            set this.u2 = u2
            set this.lifedrain = lifedrain*T32_PERIOD
            set this.manadrain = 0.0
            set this.duration = duration
            set this.breakpoint = breakpoint*breakpoint
            set this.eventkey = eventkey
            set this.e1 = AddSpecialEffectTarget(e1,u1,apoint1)
            set this.e2 = AddSpecialEffectTarget(e2,u2,apoint2)
            set this.at = at
            set this.dt = dt
            set this.lifedamage = this.lifedrain
            set this.manadamage = this.manadrain
            set this.isLife = true 
            set this.isMana = false
            set this.light = Lightning.unitToUnit(u1,u2,thistype.getZ(u1),thistype.getZ(u2),false,0.0,lfx,this.eventkey)
            call this.startPeriodic()
            return this
        endmethod
        
        static method mana takes unit u1, unit u2, real manadrain, real duration,real breakpoint,string lfx,  string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = u1
            set this.u2 = u2
            set this.lifedrain = 0.0
            set this.manadrain = manadrain*T32_PERIOD
            set this.duration = duration
            set this.breakpoint = breakpoint*breakpoint
            set this.eventkey = eventkey
            set this.e1 = AddSpecialEffectTarget(e1,u1,apoint1)
            set this.e2 = AddSpecialEffectTarget(e2,u2,apoint2)
            set this.at = at
            set this.dt = dt
            set this.lifedamage = this.lifedrain
            set this.manadamage = this.manadrain
            set this.isLife = false 
            set this.isMana = true
            set this.light = Lightning.unitToUnit(u1,u2,thistype.getZ(u1),thistype.getZ(u2),false,0.0,lfx,this.eventkey)
            call this.startPeriodic()
            return this
        endmethod
        
        static method lifeMana takes unit u1, unit u2, real lifedrain, real manadrain, real duration,real breakpoint,string lfx,  string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = u1
            set this.u2 = u2
            set this.lifedrain = lifedrain*T32_PERIOD
            set this.manadrain = manadrain*T32_PERIOD
            set this.duration = duration
            set this.breakpoint = breakpoint*breakpoint
            set this.eventkey = eventkey
            set this.e1 = AddSpecialEffectTarget(e1,u1,apoint1)
            set this.e2 = AddSpecialEffectTarget(e2,u2,apoint2)
            set this.lifedamage = this.lifedrain
            set this.manadamage = this.manadrain
            set this.isLife = true 
            set this.isMana = true
            set this.light = Lightning.unitToUnit(u1,u2,thistype.getZ(u1),thistype.getZ(u2),false,0.0,lfx,this.eventkey)
            call this.startPeriodic()
            return this
        endmethod
        
        static method lifeEx takes unit u1, unit u2, real lifedrain, real lifedamage, real duration,real breakpoint,string lfx,  string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey returns thistype
            local thistype this = thistype.new()
            set this.u1 = u1
            set this.u2 = u2
            set this.lifedrain = lifedrain*T32_PERIOD
            set this.manadrain = 0.0
            set this.duration = duration
            set this.breakpoint = breakpoint*breakpoint
            set this.eventkey = eventkey
            set this.e1 = AddSpecialEffectTarget(e1,u1,apoint1)
            set this.e2 = AddSpecialEffectTarget(e2,u2,apoint2)
            set this.at = at
            set this.dt = dt
            set this.lifedamage = lifedamage*T32_PERIOD
            set this.manadamage = this.manadrain
            set this.isLife = true 
            set this.isMana = false
            set this.light = Lightning.unitToUnit(u1,u2,thistype.getZ(u1),thistype.getZ(u2),false,0.0,lfx,this.eventkey) 
            call this.startPeriodic()
            return this
        endmethod
        
        static method manaEx takes unit u1, unit u2, real manadrain, real manadamage, real duration,real breakpoint,string lfx,  string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = u1
            set this.u2 = u2
            set this.lifedrain = 0.0
            set this.manadrain = manadrain*T32_PERIOD
            set this.duration = duration
            set this.breakpoint = breakpoint*breakpoint
            set this.eventkey = eventkey
            set this.e1 = AddSpecialEffectTarget(e1,u1,apoint1)
            set this.e2 = AddSpecialEffectTarget(e2,u2,apoint2)
            set this.at = at
            set this.dt = dt
            set this.lifedamage = this.lifedrain
            set this.manadamage = manadamage*T32_PERIOD
            set this.isLife = false
            set this.isMana = true 
            set this.light = Lightning.unitToUnit(u1,u2,thistype.getZ(u1),thistype.getZ(u2),false,0.0,lfx,this.eventkey)
            call this.startPeriodic()
            return this
        endmethod
        
        static method lifeManaEx takes unit u1, unit u2, real lifedrain, real lifedamage, real manadrain, real manadamage,real breakpoint,string lfx,  real duration, string e1, string e2, string apoint1, string apoint2, attacktype at, damagetype dt,integer eventkey  returns thistype
            local thistype this = thistype.new()
            set this.u1 = u1
            set this.u2 = u2
            set this.lifedrain = lifedrain*T32_PERIOD
            set this.manadrain = manadrain*T32_PERIOD
            set this.duration = duration
            set this.breakpoint = breakpoint*breakpoint
            set this.eventkey = eventkey
            set this.e1 = AddSpecialEffectTarget(e1,u1,apoint1)
            set this.e2 = AddSpecialEffectTarget(e2,u2,apoint2)
            set this.lifedamage = lifedamage*T32_PERIOD
            set this.manadamage = manadamage*T32_PERIOD
            set this.isLife = true 
            set this.isMana = true
            set this.light = Lightning.unitToUnit(u1,u2,thistype.getZ(u1),thistype.getZ(u2),false,0.0,lfx,this.eventkey)
            call this.startPeriodic()
            return this
        endmethod
        
        implement init
    endstruct
    
endlibrary

Samples


JASS:
library FoD initializer init requires DrainSystem

    globals
        private constant integer abil = 'A000'
        private constant string fx = "Abilities\\Spells\\Other\\SoulBurn\\SoulBurnbuff.mdl"
        private constant string fx2 = "Abilities\\Spells\\Human\\InnerFire\\InnerFireTarget.mdl"
        private constant string drainfx = "AFOD"
        private constant string point = "overhead"
        private constant string point2 = "overhead"
        private unit u = null
    endglobals
    
    private function drain takes nothing returns nothing
        set u = GetTriggerUnit()
        call Drain.lifeEx(u,GetSpellTargetUnit(),GetUnitAbilityLevel(u,abil)*GetHeroStr(u,true),GetUnitAbilityLevel(u,abil)*GetHeroInt(u,true), 5.0,800.0,drainfx,fx2,fx,point2,point,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_DIVINE,abil)
    endfunction
    
    private function break takes nothing returns nothing
        call BJDebugMsg("Finger of death was broken.")
    endfunction
    
    private function end takes nothing returns nothing
        call SetUnitState(Drain.getTriggeringDrain().u2,UNIT_STATE_MANA,0.0)
    endfunction
    
    private function init takes nothing returns nothing
        call RegisterSpellEffectEvent(abil,function drain)
        call Drain.registerBreakEvent(abil,function break)
        call Drain.registerEndEvent(abil,function end)
    endfunction
    
endlibrary


JASS:
library ForkedDrain initializer init requires DrainSystem

    globals
        private constant integer abil = 'A001'
        private constant string fx = "Abilities\\Spells\\Other\\Drain\\DrainTarget.mdl"
        private constant string fx2 = "Abilities\\Spells\\Other\\Drain\\DrainTarget.mdl"
        private constant string drainfx = "DRAB"
        private constant string point = "overhead"
        private constant string point2 = "overhead"
        private constant real radius = 150.0
        private constant integer TARGETS = 2
        private integer maxtargs
        private integer curtargs = 1
        private unit u = null
        private unit tmpU = null
        private unit tmpUo = null
        private group tmpGroup = CreateGroup()
        private integer level
    endglobals
    
    private function filter takes nothing returns boolean
        set tmpU = GetFilterUnit()
        if IsUnitEnemy(tmpU,GetOwningPlayer(u)) and GetWidgetLife(tmpU) > .405 and (not IsUnitType(tmpU,UNIT_TYPE_STRUCTURE)) and curtargs < maxtargs and tmpU != tmpUo then
            call Drain.life(u,tmpU,level*20,5.0,800.0,drainfx,fx2,fx,point2,point,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_DIVINE,abil)
            set curtargs = curtargs + 1
        endif
        return false
    endfunction
    
    private function drain takes nothing returns nothing
        set u = GetTriggerUnit()
        set level = GetUnitAbilityLevel(u,abil)
        set tmpUo = GetSpellTargetUnit()
        call Drain.life(u,tmpUo,level*20,5.0,800.0,drainfx,fx2,fx,point2,point,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_DIVINE,abil)
        set maxtargs = TARGETS*level
        call GroupEnumUnitsInRange(tmpGroup, GetUnitX(tmpUo), GetUnitY(tmpUo), radius*level, Filter(function filter))
        set curtargs = 1
    endfunction
    
    private function dead takes nothing returns nothing
        call BJDebugMsg(GetUnitName(Drain.getTriggeringDrain().u2) + " has died from Forked Drain.")
    endfunction
    
    private function init takes nothing returns nothing
        call RegisterSpellEffectEvent(abil,function drain)
        call Drain.registerDeathEvent(abil,function dead)
    endfunction
    
endlibrary

Credits






v1.01 - fixed things
v1.02 - added a new event handler for when the caster dies
- made the drain end when the caster dies (I wonder why I didn't from the start)
- added global event handlers for all the five event handlers


Keywords:
adiktuz,scrolls,lanthanum,system,spell,drain,life,mana,damage,siphon
Contents

Drain System 1.02 (Map)

Reviews
04:29, 20th Oct 2012 Magtheridon96: Approved.
One thing I forgot to mention in the review:

JASS:
if IsUnitType(u,UNIT_TYPE_FLYING) then
    return flyzbuffer
else
    return zbuffer
endif
->
JASS:
if IsUnitType(u,UNIT_TYPE_FLYING) then
    return flyzbuffer
endif
return zbuffer

and

JASS:
local thistype this
if (recycle == 0) then
    set instanceCount = instanceCount + 1
    return instanceCount
else
    set this = recycle
    set recycle = recycle.recycleNext
endif
return this
->
JASS:
local thistype this = recycle
if (this == 0) then
    set instanceCount = instanceCount + 1
    return instanceCount
endif
set recycle = recycle.recycleNext
return this

:p

Also, you can add booleans to the struct to determine whether the ability only does life drain/mana drain.
This way, your periodic static method would have less of an effect on the game because it would only be making function calls if needed :D

One other very tiny improvement would be to cache unit coordinates in the periodic function since there are many calls in there o_O

JASS:
local real x = GetUnitX(this.u1) - GetUnitX(this.u2)
local real y = GetUnitY(this.u1) - GetUnitY(this.u2)

// distance would then be x*x + y*y

:D
 
@Maggy - okay, I'll update it maybe tonight after I get back home... I'll study the Event library first... :)

@FRENGERS - I never said it was impossible, I said it was a pain to do... and you need some other system if you want the bonus damage to stay after the drain... and that is totally out of my plans for now... and it's not that useful, at least not on most custom maps that uses their own damage system...

@baassee - I think it's because of the spider's attack animation (if you're talking about the discrepancy in the drain's distance from one of the spideys...
 

Updated...

Btw, Lightning was actually created because of this system (the idea of a Drain system crossed my mind before the idea of the Lightning)...

and, I won't be running events Blizz-like by utilizing Event because that would defeat the purpose of making the event handling simpler for the user...


Updated!

Made the drain end when the caster dies when I realized that I haven't had that feature... and of course added an event handler for that... take note that the event handler will run for all the current drains of the caster so for example in Forked Drain, you have 3 targets then you died, it will run three times...

Also added global event handlers for all the five event handlers... Global meaning event handlers that will fire for all drains... they are toggled via constant booleans and static ifs so that the system won't include them if they're not gonna be used... :)

EDIT: I will add a global event handler for drain start so that you can fire a general event for all drains that have started...
 
Last edited:
Level 4
Joined
Apr 19, 2013
Messages
86
Hey man,

Awesome system,

I wanted to use the Forked Drain, but more as a passive. How would I got about changing the event from the ability init as an active, to a percentage chance (maybe 30%) to proc when the hero auto attacks? I still want forked lightning to be associated with an ability, so it shows the ability on the skill console, but as a just passive. and if the hero learns Forked lightning passive, the trigger will be ready to handle the auto attack percentage event from that point on.

Do you know what I mean?
 
Level 4
Joined
Apr 19, 2013
Messages
86
Ok, I'll give it a whack. Can you tell me which line of code starts the actions? (event, if it's still called that?) I'm assuming it would be something like unit uses ability 'A001' or something. But I couldn't find it for the life of me.

My goal is pretty simple, I don't think I need a dds. I'll show you what I mean in GUI since its a little easier for me.

  • Events
    • Unit - A unit Is attacked
  • Conditions
    • And - All (Conditions) are true
      • Conditions
        • (Attacking unit) Equal to ForkedDrainCaster
        • (Random integer number between 1 and 10) Greater than 6
  • Actions
    • Custom script: run the forked drain trigger?
ForkedDrainCaster can be set externally whenever a hero learns forked lightning as a skill, or something to that effect. I'd imagine also under actions we should define forked drain's target variables. How many variables like that would have to be defined in order for the drain system to distinguish the target and such? For the actions we could throw in some custom script to run forked lightning as it's supposed to, without changing the system too much. Would this way work, using this imple gui approach to determine whether or not to trigger forked drain?
 
Top