• 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.

[vJASS] Basic DPS System + SFX (no buff)

Status
Not open for further replies.
Level 7
Joined
Apr 30, 2011
Messages
359
The System Draft:
JASS:
library DPS requires AutoIndex
    
    globals
        constant real DEFAULT_INTERVAL_TIME = 0.01
        constant attacktype      DEFAULT_AT = ATTACK_TYPE_NORMAL
        constant damagetype      DEFAULT_DT = DAMAGE_TYPE_MAGIC
        constant string  DEFAULT_ATTACHMENT = "chest"
    endglobals
    
    private struct DPS
        private unit     source
        private group    target
        private real     damage
        private attacktype   AT
        private damagetype   DT
        private integer     cur
        private integer     max
        private effect array SE [8190]
        private string      SES
        private string   DPSSES
        private string   eAttP1
        private string   eAttP2
        
        private real          x
        private real          y
        private real     radius
        private boolexpr filter
        private effect    AoESE
        
        private static thistype array Index [8190]
        private static integer        Total = 0
        
        private static integer        tempI = 0
        private static group          tempG
        
        private static method attachSE takes nothing returns nothing
            set .Index [.tempI].SE [GetUnitId(GetEnumUnit())] = AddSpecialEffectTarget(.Index [.tempI].SES, GetEnumUnit(), .Index [.tempI].eAttP2)
        endmethod
        
        private static method detachSE takes nothing returns nothing
            call DestroyEffect(.Index [.tempI].SE [GetUnitId(GetEnumUnit())])
        endmethod
        
        private static method damageGroup takes nothing returns nothing
            call UnitDamageTarget(.Index [.tempI].source, GetEnumUnit(), .Index [.tempI].damage, true, false, .Index [.tempI].AT, .Index [.tempI].DT, null)
            call DestroyEffect(AddSpecialEffectTarget(.Index [.tempI].DPSSES, GetEnumUnit(), .Index [.tempI].eAttP2))
        endmethod
        
        private static method Expire takes nothing returns nothing
            local integer i = GetTimerData(GetExpiredTimer())
            
            set .tempI = i
            call ForGroup(.Index [i].target, function thistype.damageGroup)
            
            set .Index [i].cur = .Index [i].cur + 1
            
            if .Index [i].cur == .Index [i].max then
                call ForGroup(.Index [i].target, function thistype.detachSE)
                call ReleaseTimer(GetExpiredTimer())
                
                call .Index [i].destroy()
            endif
        endmethod
        
        static method Start takes string se, string dpsse, string attachp1, string attachp2, unit source, group target, real damage, attacktype atype, damagetype dtype, real interval, integer count returns nothing
            local integer a = 1
            local integer b = .Total + 1
            
            local integer i = 0
            
            loop
                exitwhen a == b
                
                if .Index [a] == 0 then
                    set i = a
                    
                    set a = b
                endif
                
                set a = a + 1
            endloop
            
            if i == 0 then
                set     .Total  = .Total + 1
                set i = .Total
            endif
            
            set .Index [i] = .create()
            set .Index [i].source = source
            set .Index [i].target = target
            set .Index [i].damage = damage
            set .Index [i].AT     = atype
            set .Index [i].DT     = dtype
            set .Index [i].cur    = 0
            set .Index [i].max    = count
            set .Index [i].SES    = se
            set .Index [i].DPSSES = dpsse
            set .Index [i].eAttP1 = attachp1
            set .Index [i].eAttP2 = attachp2
            
            set .tempI  = i
            call ForGroup(target, function thistype.attachSE)
            
            call TimerStart(NewTimerEx(i), interval, true, function thistype.Expire)
        endmethod
        
        private static method filterUnitNew takes nothing returns nothing
            if IsUnitInGroup(GetEnumUnit(), .Index [.tempI].target) then
                call GroupRemoveUnit(.tempG, GetEnumUnit())
            endif
        endmethod
        
        private static method filterUnitOut takes nothing returns nothing
            if IsUnitInGroup(GetEnumUnit(), .tempG) then
                call GroupRemoveUnit(.Index [.tempI].target, GetEnumUnit())
            endif
        endmethod
        
        private static method ExpireArea takes nothing returns nothing
            local integer i = GetTimerData(GetExpiredTimer())
            local group   g = CreateGroup()
            local group new
            local group out
            
            set .tempI = i
            call GroupEnumUnitsInRange(g, .Index [i].x, .Index [i].y, .Index [i].radius, .Index [i].filter)
            set .tempG = g
            call ForGroup(.tempG, function thistype.filterUnitNew)
            set new = .tempG
            set .tempG = g
            call ForGroup(.Index [i].target, function thistype.filterUnitOut)
            set out = .Index [i].target
            set .Index [i].target = g
            
            call ForGroup(g, function thistype.damageGroup)
            call ForGroup(new, function thistype.attachSE)
            call ForGroup(out, function thistype.detachSE)
            
            set .Index [i].cur = .Index [i].cur + 1
            
            if .Index [i].cur == .Index [i].max then
                call ForGroup(g, function thistype.detachSE)
                call ReleaseTimer(GetExpiredTimer())
                
                call .Index [i].destroy()
            endif
            
            call DestroyGroup(g)
            call DestroyGroup(new)
            call DestroyGroup(out)
            set g   = null
            set new = null
            set out = null
        endmethod
        
        static method StartArea takes string aoese, string se, string dpsse, string attachp1, string attachp2, unit source, real x, real y, real radius, code filter, real damage, attacktype atype, damagetype dtype, real interval, integer count returns nothing
            local integer a = 1
            local integer b = .Total + 1
            
            local integer i = 0
            local group   g = CreateGroup()
            
            loop
                exitwhen a == b
                
                if .Index [a] == 0 then
                    set i = a
                    
                    set a = b
                endif
                
                set a = a + 1
            endloop
            
            if i == 0 then
                set     .Total  = .Total + 1
                set i = .Total
            endif
            
            call GroupEnumUnitsInRange(g, x, y, radius, Filter(filter))
            
            set .Index [i] = .create()
            set .Index [i].source = source
            set .Index [i].target = g
            set .Index [i].x      = x
            set .Index [i].y      = y
            set .Index [i].radius = radius
            set .Index [i].filter = Filter(filter)
            set .Index [i].damage = damage
            set .Index [i].AT     = atype
            set .Index [i].DT     = dtype
            set .Index [i].cur    = 0
            set .Index [i].max    = count
            set .Index [i].SES    = se
            set .Index [i].DPSSES = dpsse
            set .Index [i].eAttP1 = attachp1
            set .Index [i].eAttP2 = attachp2
            set .Index [i].AoESE  = AddSpecialEffect(aoese, x, y)
            
            set .tempI  = i
            call ForGroup(g, function thistype.attachSE)
            
            call DestroyGroup(g)
            set g = null
            
            call TimerStart(NewTimerEx(i), interval, true, function thistype.ExpireArea)
        endmethod
    endstruct
    
    public function Target takes string se, string dpsse, unit source, unit target, real tdamage, real ttime returns nothing
        local group   g = CreateGroup()
        local real    d = tdamage * DEFAULT_INTERVAL_TIME / ttime
        local integer c = R2I(ttime / DEFAULT_INTERVAL_TIME)
        
        call GroupAddUnit(g, target)
        
        call DPS.Start(se, dpsse, DEFAULT_ATTACHMENT, DEFAULT_ATTACHMENT, source, g, d, DEFAULT_AT, DEFAULT_DT, DEFAULT_INTERVAL_TIME, c)
        
        call DestroyGroup(g)
        set g = null
    endfunction
    
    public function TargetEx takes string se, string attse, string dpsse, string attdpsse, unit source, unit target, real tdamage, attacktype atype, damagetype dtype, real itime, real ttime returns nothing
        local group   g = CreateGroup()
        local real    d = tdamage * itime / ttime
        local integer c = R2I(ttime / itime)
        
        call GroupAddUnit(g, target)
        
        call DPS.Start(se, dpsse, attse, attdpsse, source, g, d, atype, dtype, itime, c)
        
        call DestroyGroup(g)
        set g = null
    endfunction
    
    public function Group takes string se, string dpsse, unit source, group target, real tdamage, real ttime returns nothing
        local real    d = tdamage * DEFAULT_INTERVAL_TIME / ttime
        local integer c = R2I(ttime / DEFAULT_INTERVAL_TIME)
        
        call DPS.Start(se, dpsse, DEFAULT_ATTACHMENT, DEFAULT_ATTACHMENT, source, target, d, DEFAULT_AT, DEFAULT_DT, DEFAULT_INTERVAL_TIME, c)
    endfunction
    
    public function GroupEx takes string se, string attse, string dpsse, string attdpsse, unit source, group target, real tdamage, attacktype atype, damagetype dtype, real itime, real ttime returns nothing
        local real    d = tdamage * itime / ttime
        local integer c = R2I(ttime / itime)
        
        call DPS.Start(se, dpsse, attse, attdpsse, source, target, d, atype, dtype, itime, c)
    endfunction
    
    public function Area takes string aoese, string se, string dpsse, unit source, real x, real y, real radius, real tdamage, real ttime, code filter returns nothing
        local real    d = tdamage * DEFAULT_INTERVAL_TIME / ttime
        local integer c = R2I(ttime / DEFAULT_INTERVAL_TIME)
        
        call DPS.StartArea(aoese, se, dpsse, DEFAULT_ATTACHMENT, DEFAULT_ATTACHMENT, source, x, y, radius, filter, d, DEFAULT_AT, DEFAULT_DT, DEFAULT_INTERVAL_TIME, c)
    endfunction
    
    public function AreaEx takes string aoese, string se, string attse, string dpsse, string attdpsse, unit source, real x, real y, real radius, real tdamage, attacktype atype, damagetype dtype, real itime, real ttime, code filter returns nothing
        local real    d = tdamage * itime / ttime
        local integer c = R2I(ttime / itime)
        
        call DPS.StartArea(aoese, se, dpsse, attse, attdpsse, source, x, y, radius, filter, d, atype, dtype, itime, c)
    endfunction
endlibrary

Notes:
- See all available APIs on the bottom of the system
- That library prefers 100% accuracy (use so much timer), so you must use Group functions more than Target functions
- If you need to use Target functions really much, then use TargetEx function and use larger interval (default if you are using Target function is 0.01 interval, which can cause great lags if you use too much)
- Sorry, no documentation

Please comments and gives suggestions!
 
Last edited:
If u make the special effect an array with 8190 as a size, you would only have the ability to create one struct instance.
You should only have 1 effect. If you want more than one, feel free to use Bribe's Table.
Instead of AutoIndex, use UnitIndexer. It's faster, cleaner and bugless.

This has a lot of overhead at the moment. Local group variables are really slow.
You don't need groups at all for this
You only need to store 2 units and some damage constants.
You'd only need one timer for this. It would loop through all units and deal damage.
Check out my Heal system to see a pretty good model of a Dps system.
All you'd have to do is damage instead of set life.
 
Level 7
Joined
Apr 30, 2011
Messages
359
aren't thistype array with normal thistype different?
i only know that array one doesn't have any restrictions with struct instance (i only know this)
if it does have any restriction . . . . then i'll fix it

about using only one timer, i'll make one system that use that . . . . (since there's users that will use not only 1 interval type)

and one more . . .
are you ok for me to edit your system?
i should not do that :3
just analyze is enough . . .
 
It's actually this:
private effect array SE [8190]
That's going to cause issues :eek:
It's going to make the max struct instances allowed be exactly 1 (8190 max / 8190 effects per instance = 1)

and one more . . .
are you ok for me to edit your system?
i should not do that :3
just analyze is enough . . .

I'm ok with that, but "If you give a man a fish, you'll feed him for a day. If you teach a man to fish, you'll feed him for a lifetime.", so I guess it's better if you use it as a reference :>
 
Level 7
Joined
Apr 30, 2011
Messages
359
It's actually this:
private effect array SE [8190]
That's going to cause issues :eek:
It's going to make the max struct instances allowed be exactly 1 (8190 max / 8190 effects per instance = 1)

aren't its max struct instances already 1 without that SE variable . . .
since there is thistype array Index [8190] . . . . .
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
The static variables are created exactly as global variables. Static methods are created exactly as standard functions. Instance methods are functions that take the integer index of the struct instance that is calling them. This is hidden from you.

Declaring statics is like declaring globals. Since there is only one instance of them that needs to be worried about, you can pretty much do whatever you want with them.
 
Status
Not open for further replies.
Top