Diablo 3 Spells #2

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
2nd spellpack
includes grenade, multishoot and poision darts
requires TimerUtils and my math (more like random stuff) and vectors library
same as in the other i'm not going to update this any more

you can use and edit the spells if you give credits

thanks to Toadcop for the ProjToPoint function (inside vectors) and paladon for DOT

Keywords:
Diablo, Diablo 3, jump, charge, locust, swarm, lightning, twister, magic, tristam, borderlands, halls of agony
Contents

Noch eine WARCRAFT-III-Karte (Map)

Reviews
12th Dec 2015 IcemanBo: For too long time as NeedsFix. Rejected. 19th Jul 2011 Bribe: This is a hard thing to import because you made a really bad library requirement: Math. You use the word "Loc" in functions that expect coordinates as...

Moderator

M

Moderator

12th Dec 2015
IcemanBo: For too long time as NeedsFix. Rejected.

19th Jul 2011
Bribe:

This is a hard thing to import because you made a really bad
library requirement: Math. You use the word "Loc" in functions
that expect coordinates as arguments, and your item check
should compare that the distance between the item and where
it should be is equal to 0, not less than .1.

Math uses Vector struct types but doesn't list Vector as a require-
ment.

Vector uses Math...

It looks like you stole Anitarf's Vector, added some things and
posted it here...

Poison Darts is vJass but uses udg_ variables...?
 
Level 14
Joined
Nov 23, 2008
Messages
512
Poision Darts
JASS:
//TESH.scrollpos=12
//TESH.alwaysfold=0
library PoisionDarts requires Math
    globals
        private constant real Tick = 1./30.
        
        private constant real Speed = 1000.
        private constant real DotInterval=0.1
        private attacktype Attacktype = ATTACK_TYPE_PIERCE
        private damagetype Damagetype = DAMAGE_TYPE_DEMOLITION
        private string DeadEffect = ""
        
        private constant integer DartUnit = 'h002'
        private constant integer PoisionDartSpellID = 'AOsw'
    endglobals
    
    struct Dart
        unit Caster
        unit Dart
        real Damage
        real DistanceLeft
        real DotDamage
        real DotDuration
        string DotEffect
        
        vector position
        vector velocity
        
        
        private integer di
        
        private static timer dTim           = CreateTimer()
        private static integer dTotal       = 0
        private static thistype array dDarts
        private static group g              = CreateGroup()
        private static thistype temp
        private static boolean hit          = false
        
        private method onDestroy takes nothing returns nothing
            set dTotal = dTotal - 1            
            set dDarts[di] = dDarts[dTotal]
            set dDarts[di].di=di
            if dTotal == 0 then
                call PauseTimer(dTim)
            endif
        endmethod
        
        private static method DamageUnits takes nothing returns nothing
            if IsUnitEnemy(GetEnumUnit(), GetOwningPlayer(temp.Caster)) and not hit then
                call UnitDamageTarget(temp.Caster,GetEnumUnit(),temp.Damage,true, false, Attacktype, Damagetype, WEAPON_TYPE_WHOKNOWS)
                set udg_DTA_Target = GetEnumUnit()
                set udg_DTA_DmgDealer = temp.Caster
                set udg_DTA_TotalDamageDealt = temp.DotDamage
                set udg_DTA_Time = temp.DotDuration
                set udg_DTA_Interval = DotInterval
                set udg_DTA_SpecialEffect = temp.DotEffect
                set udg_DTA_EffectAttachmentPoint = "origin"
                set udg_DTA_Attacktype = Attacktype
                set udg_DTA_DamageType = Damagetype
                call TriggerExecute( gg_trg_Get_DOT )
                set hit=true
            endif
        endmethod
        
        private static method onLoop takes nothing returns nothing
            local thistype dat
            local integer i2 = 0
            loop
                exitwhen i2 > dTotal - 1
                set dat = dDarts[i2]
                set dat.DistanceLeft = dat.DistanceLeft - (Speed * Tick)
                call dat.position.add(dat.velocity)
                call SetUnitXYZ(dat.Dart,dat.position.x,dat.position.y,dat.position.z)
                set temp=dat
                call GroupEnumUnitsInRange(g,dat.position.x,dat.position.y,40.,null)
                call ForGroup(g,function thistype.DamageUnits)
                    
                call GroupClear(g)
                if (dat.DistanceLeft <=0. or GetLocZ(dat.position.x,dat.position.y)> dat.position.z or hit) then
                    call RemoveUnit(dat.Dart)
                    call DestroyEffect(AddSpecialEffect(DeadEffect,dat.position.x,dat.position.y))
                    call dat.position.destroy()
                    call dat.velocity.destroy()
                    set dat.Caster=null
                    set dat.Dart=null
                    call dat.destroy()
                    set hit=false
                endif
                set i2 = i2+1
            endloop
        endmethod
        
        static method NewDart takes unit caster, vector target ,real damage, real distance, real dot, real dotdur, string doteffect, real scale returns nothing
            local thistype dat
            local vector dir
            set dat = thistype.allocate()
            if dTotal==0 then
                call TimerStart(dTim,Tick,true,function thistype.onLoop)
            endif
            set dat.di=dTotal
            set dDarts[dat.di] = dat
            set dTotal = dTotal+1     
            set dat.Caster = caster
            set dat.Damage = damage
            set dat.DistanceLeft = distance
            set dat.DotDamage=dot
            set dat.DotDuration=dotdur
            set dat.DotEffect=doteffect
            set dat.position = vector.create(GetUnitX(dat.Caster),GetUnitY(dat.Caster),GetUnitZ(dat.Caster)+40.)
            set dir=vector.difference(target,dat.position)
            call dir.vecNormalise()
            set dat.velocity = vector.create(Speed*Tick*dir.x,Speed*Tick*dir.y,Speed*Tick*dir.z)
            set dat.Dart = CreateUnit(GetOwningPlayer(dat.Caster),DartUnit,dat.position.x,dat.position.y,Atan(dat.velocity.y/dat.velocity.x)*bj_RADTODEG)
            call MakeUnitFly(dat.Dart)
            call SetUnitZ(dat.Dart,dat.position.z)
            call SetUnitScale(dat.Dart,scale,scale,scale)
        endmethod
    endstruct
    
    private struct PoisionDart
        unit Caster
        integer DartsLeft
        integer SpellLevel
        real ShootDelay
        real DartDamage
        real ShootDistance
        real OverTimeDamage
        real OverTimeDamageDuration
        string OverTimeDamageEffect 
        real Scale
        vector target
        timer tim
        
        
        //============================ settings ==============================
        private static method GetDistance takes integer level returns real
            return 700.
        endmethod
        
        private static method GetDamage takes integer level returns real
            return 30.+(15*I2R(level))
        endmethod
        
        private static method GetDartCount takes integer level returns integer
            return 5+(2*level)
        endmethod
        
        private static method GetShootDelay takes integer level returns real
            return 0.1
        endmethod
        
        private static method GetDamageOverTime takes integer level returns real
            return 10.+(5.*level)
        endmethod
        
        private static method GetDamageOverTimeDuration takes integer level returns real
            return 5.
        endmethod
        //========================== end of settings =========================
        private static method onEnd takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local timer t2
            local thistype dat = PoisionDart(GetTimerData(t))
            if (dat.DartsLeft >0) then
                set dat.DartsLeft=dat.DartsLeft-1
                call Dart.NewDart(dat.Caster,dat.target,dat.DartDamage,dat.ShootDistance,dat.OverTimeDamage,dat.OverTimeDamageDuration,dat.OverTimeDamageEffect,dat.Scale)
                call StartSound(gg_snd_RainOfFireTarget1) // RainOfFireTarget1 ersetzten
                set t = NewTimer()
                call SetTimerData(t, dat)
                call TimerStart(t, dat.ShootDelay, false, function thistype.onEnd)
            else
                set dat.Caster=null
                call dat.target.destroy()
                call dat.destroy()
            endif
        endmethod
        private static method Check takes nothing returns boolean
            local thistype dat
            local timer t
            if GetSpellAbilityId() == PoisionDartSpellID then
                call StartSound(gg_snd_RainOfFireTarget1) // RainOfFireTarget1 ersetzten
                set dat = thistype.allocate()
                set dat.SpellLevel = GetUnitAbilityLevel(GetTriggerUnit(), PoisionDartSpellID)
                set dat.DartsLeft = GetDartCount(dat.SpellLevel)-1+GetNumberOfItemsFromUnit(GetTriggerUnit(),'I000') //rune id
                set t = NewTimer()
                call SetTimerData(t, dat)
                set dat.ShootDelay=GetShootDelay(dat.SpellLevel)//-(0.02*GetNumberOfItemsFromUnit(GetTriggerUnit(),'I000')) // rune id
                set dat.Caster = GetTriggerUnit()
                set dat.DartDamage = GetDamage(dat.SpellLevel)+(10*GetNumberOfItemsFromUnit(GetTriggerUnit(),'I000')) // rune id
                set dat.ShootDistance = GetDistance(dat.SpellLevel)+(100*GetNumberOfItemsFromUnit(GetTriggerUnit(),'I000')) // rune id
                set dat.target = vector.create(GetSpellTargetX(),GetSpellTargetY(),GetLocZ(GetSpellTargetX(),GetSpellTargetY())+40.)
                set dat.OverTimeDamage = GetDamageOverTime(dat.SpellLevel)
                set dat.OverTimeDamageDuration = GetDamageOverTimeDuration(dat.SpellLevel)
                set dat.OverTimeDamageEffect="" //DoT effect
                if GetNumberOfItemsFromUnit(GetTriggerUnit(),'I000') > 0 then //rune id
                    set dat.Scale=2.
                else
                    set dat.Scale=1.
                endif
                call TimerStart(t, dat.ShootDelay, false, function thistype.onEnd)
            endif
            return false
        endmethod
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.Check))
        endmethod
    endstruct
endlibrary
Grenade
JASS:
//TESH.scrollpos=30
//TESH.alwaysfold=0
library Grenade requires Math
    globals
        private constant real Tick = 1./30.
        private constant real Gravity = -5.
        
        private constant real Speed = 50.
        private constant real BounceFactor = 0.5
        private string NormalEffect="Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
        private attacktype Attacktype = ATTACK_TYPE_MELEE
        private damagetype Damagetype = DAMAGE_TYPE_DEMOLITION
        
        private constant integer GrenadeUnit = 'h000'
        private constant integer GrenadeSpellID = 'AUcs'
    endglobals
    
    private struct Grenade
        unit Caster
        unit Grenade
        real Damage
        real AOE
        real Duration
        real Bounce
        real Slow //slowmo effect
        string Effect
        
        vector position
        vector velocity
        
        private integer i
        
        private static timer Tim           = CreateTimer()
        private static integer Total       = 0
        private static thistype array Grenades
        private static group g             = CreateGroup()
        private static thistype temp
        
        //============================ settings ==============================
        private static method GetDuration takes integer level returns real
            return 3.
        endmethod
        
        private static method GetDamage takes integer level returns real
            return 30.*I2R(level)
        endmethod
        
        private static method GetAOE takes integer level returns real
            return 100.+50.*I2R(level)
        endmethod
        
        private static method GetGrenadeCount takes integer level returns integer
            return level
        endmethod
        //========================== end of settings =========================
        private static method onDamage takes nothing returns nothing
            if IsUnitEnemy(GetEnumUnit(), GetOwningPlayer(temp.Caster)) then
                call UnitDamageTarget(temp.Caster,GetEnumUnit(),temp.Damage,true, false, Attacktype, Damagetype, WEAPON_TYPE_WHOKNOWS)
            endif
        endmethod
        
        
        private method onDestroy takes nothing returns nothing
            set Total = Total - 1            
            set Grenades[i] = Grenades[Total]
            set Grenades[i].i=i
            if Total == 0 then
                call PauseTimer(Tim)
            endif
        endmethod
        
        private static method onLoop takes nothing returns nothing
            local thistype dat
            local integer i2 = 0
            loop
                exitwhen i2 > Total - 1
                set dat = Grenades[i2]
                set dat.Duration = dat.Duration-(Tick*dat.Slow)
                set dat.velocity.z=dat.velocity.z+(Gravity*dat.Slow)
                call dat.position.addscaled(dat.velocity,dat.Slow)
                call SetUnitXYZ(dat.Grenade,dat.position.x,dat.position.y,dat.position.z)
                if dat.position.z<=GetLocZ(dat.position.x,dat.position.y)+1. then
                    set dat.position.z=GetLocZ(dat.position.x,dat.position.y)+1.5
                    call dat.velocity.vecBounce(dat.position.x,dat.position.y,dat.Bounce)
                    call dat.velocity.scale(0.925)
                endif
                if dat.Duration <=0. then
                    set temp = dat
                    call GroupEnumUnitsInRange(g,dat.position.x,dat.position.y,dat.AOE,null)
                    call ForGroup(g,function thistype.onDamage)
                    call GroupClear(g)
                    call RemoveUnit(dat.Grenade)
                    call DestroyEffect(AddSpecialEffect(NormalEffect,dat.position.x,dat.position.y))
                    call DestroyEffect(AddSpecialEffect(dat.Effect,dat.position.x,dat.position.y))
                    call dat.position.destroy()
                    call dat.velocity.destroy()
                    set dat.Caster=null
                    set dat.Grenade=null
                    call dat.destroy()
                endif
                set i2 = i2+1
            endloop
        endmethod
        
        private static method Check takes nothing returns boolean
            local thistype dat
            local integer x =0
            local real speedleft
            local real targetx
            local real targety
            local integer lvl = GetUnitAbilityLevel(GetTriggerUnit(), GrenadeSpellID)
            if GetSpellAbilityId() == GrenadeSpellID then
                loop
                    exitwhen x > GetGrenadeCount(lvl)-1+GetNumberOfItemsFromUnit(GetTriggerUnit(),'I000')
                    set dat = thistype.allocate()
                    if Total==0 then
                        call TimerStart(Tim,Tick,true,function thistype.onLoop)
                    endif
                    set dat.i=Total
                    set Grenades[dat.i] = dat
                    set Total = Total+1               
                    set dat.Caster = GetTriggerUnit()
                    set dat.AOE = GetAOE(lvl)
                    set dat.Damage = GetDamage(lvl)+10*GetNumberOfItemsFromUnit(GetTriggerUnit(),'I000')
                    set dat.Duration = GetDuration(lvl)
                    set dat.position = vector.create(GetUnitX(dat.Caster),GetUnitY(dat.Caster),GetUnitZ(dat.Caster)+60.)
                    set dat.velocity = vector.create(0.,0.,0.)
                    set targetx = GetSpellTargetX() + GetRandomReal(-75.,75.)
                    set targety = GetSpellTargetY() + GetRandomReal(-75.,75.)
                    if dat.velocity.ProjToPoint(targetx-dat.position.x,targety-dat.position.y,GetLocZ(targetx,targety)-dat.position.z,Speed,Tick,Gravity) == false then
                        set dat.velocity.z = Speed*Sin(45.*bj_DEGTORAD)
                        set speedleft =  Speed*Cos(45.*bj_DEGTORAD)
                        set dat.velocity.x = speedleft*Cos(Atan2(targety-dat.position.y,targetx-dat.position.x))
                        set dat.velocity.y = speedleft*Sin(Atan2(targety-dat.position.y,targetx-dat.position.x))
                    endif
                    set dat.Slow = 0.7
                    set dat.Bounce = BounceFactor
                    set dat.Effect=""
                    set dat.Grenade = CreateUnit(GetOwningPlayer(dat.Caster),GrenadeUnit,dat.position.x,dat.position.y,0.)
                    call MakeUnitFly(dat.Grenade)
                    call SetUnitZ(dat.Grenade,dat.position.z)
                    set x=x+1
                endloop
            endif
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.Check))
        endmethod
    endstruct
endlibrary
Multishoot
JASS:
//TESH.scrollpos=6
//TESH.alwaysfold=0
library Multishoot requires Math
    globals
        private constant real Tick = 1./30.
        
        private constant real AngleBetween = 5.
        private constant real ShootOffset = 50.
        private constant real Speed = 1000.
        private attacktype Attacktype = ATTACK_TYPE_PIERCE
        private damagetype Damagetype = DAMAGE_TYPE_DEMOLITION
        private string DeadEffect = ""
        
        private constant integer ArrowUnit = 'h001'
        private constant integer MultishootSpellID = 'AHbz'
    endglobals
    
    private struct Arrow
        unit Caster
        unit Arrow
        real Damage
        real AOE
        real DistanceLeft
        string HitEffect
        group DamagedUnits = CreateGroup()
        
        vector position
        vector velocity
        
        
        private integer i
        
        private static timer Tim           = CreateTimer()
        private static integer Total       = 0
        private static thistype array Arrows
        private static group g             = CreateGroup()
        private static thistype temp
        
        //============================ settings ==============================
        private static method GetDistance takes integer level returns real
            return 650.+(75.*I2R(level))
        endmethod
        
        private static method GetDamage takes integer level returns real
            return 20.+(7.5*I2R(level))
        endmethod
        
        private static method GetAOE takes integer level returns real
            return 60.
        endmethod
        
        private static method GetArrowCount takes integer level returns integer
            return 7+(3*level)
        endmethod
        //========================== end of settings =========================
        private static method onDamage takes nothing returns nothing
            local vector unitpos = vector.create(GetUnitX(GetEnumUnit()),GetUnitY(GetEnumUnit()),GetUnitZ(GetEnumUnit()))
            if IsUnitEnemy(GetEnumUnit(), GetOwningPlayer(temp.Caster)) and Get2DDistance(temp.position,unitpos)<=temp.AOE and not IsUnitInGroup(GetEnumUnit(),temp.DamagedUnits) then
                call UnitDamageTarget(temp.Caster,GetEnumUnit(),temp.Damage,true, false, Attacktype, Damagetype, WEAPON_TYPE_WHOKNOWS)
                call DestroyEffect(AddSpecialEffectTarget(temp.HitEffect,GetEnumUnit(),"chest"))
                call GroupAddUnit(temp.DamagedUnits,GetEnumUnit())
            endif
            call unitpos.destroy()
        endmethod
        
        
        private method onDestroy takes nothing returns nothing
            set Total = Total - 1            
            set Arrows[i] = Arrows[Total]
            set Arrows[i].i=i
            if Total == 0 then
                call PauseTimer(Tim)
            endif
        endmethod
        
        private static method onLoop takes nothing returns nothing
            local thistype dat
            local integer i2 = 0
            loop
                exitwhen i2 > Total - 1
                set dat = Arrows[i2]
                set dat.DistanceLeft = dat.DistanceLeft - (Speed * Tick)
                call dat.position.add(dat.velocity)
                call SetUnitXYZ(dat.Arrow,dat.position.x,dat.position.y,dat.position.z)
                set temp = dat
                call GroupEnumUnitsInRange(g,dat.position.x,dat.position.y,dat.AOE,null)
                call ForGroup(g,function thistype.onDamage)
                call GroupClear(g)
                if dat.DistanceLeft <=0. or GetLocZ(dat.position.x,dat.position.y)> dat.position.z then
                    call RemoveUnit(dat.Arrow)
                    call DestroyEffect(AddSpecialEffect(DeadEffect,dat.position.x,dat.position.y))
                    call dat.position.destroy()
                    call dat.velocity.destroy()
                    call DestroyGroup(dat.DamagedUnits)
                    set dat.Caster=null
                    set dat.Arrow=null
                    call dat.destroy()
                endif
                set i2 = i2+1
            endloop
        endmethod
        
        private static method Check takes nothing returns boolean
            local thistype dat
            local integer x = 0
            local integer lvl
            local integer counter
            local real arrowspread
            local real angletotarget
            local real ang
            local real offsetx
            local real offsety
            if GetSpellAbilityId() == MultishootSpellID then
                call StartSound(gg_snd_RainOfFireTarget1) // RainOfFireTarget1 ersetzten
                set lvl = GetUnitAbilityLevel(GetTriggerUnit(), MultishootSpellID)
                set counter = GetArrowCount(lvl)-1+GetNumberOfItemsFromUnit(GetTriggerUnit(),'I000') //rune id
                set arrowspread = counter*AngleBetween
                set angletotarget = Atan2(GetSpellTargetY()-GetUnitY(GetTriggerUnit()),GetSpellTargetX()-GetUnitX(GetTriggerUnit()))*bj_RADTODEG
                set ang = angletotarget-(arrowspread/2)
                set offsetx = ShootOffset*Cos(angletotarget*bj_DEGTORAD)
                set offsety = ShootOffset*Sin(angletotarget*bj_DEGTORAD)
                loop
                    exitwhen x > counter
                    set dat = thistype.allocate()
                    if Total==0 then
                        call TimerStart(Tim,Tick,true,function thistype.onLoop)
                    endif
                    set dat.i=Total
                    set Arrows[dat.i] = dat
                    set Total = Total+1     
                    set ang = ang + AngleBetween
                    set dat.Caster = GetTriggerUnit()
                    set dat.AOE = GetAOE(lvl)
                    set dat.Damage = GetDamage(lvl)+(10*GetNumberOfItemsFromUnit(GetTriggerUnit(),'I000')) // rune id
                    set dat.DistanceLeft = GetDistance(lvl)
                    set dat.position = vector.create(GetUnitX(dat.Caster)+offsetx,GetUnitY(dat.Caster)+offsety,GetUnitZ(dat.Caster)+40.)
                    set dat.velocity = vector.create(Speed*Tick*Cos(ang*bj_DEGTORAD),Speed*Tick*Sin(ang*bj_DEGTORAD),0.)
                    set dat.HitEffect=""
                    set dat.Arrow = CreateUnit(GetOwningPlayer(dat.Caster),ArrowUnit,dat.position.x,dat.position.y,ang)
                    call MakeUnitFly(dat.Arrow)
                    call SetUnitZ(dat.Arrow,dat.position.z)
                    set x=x+1
                endloop
            endif
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function thistype.Check))
        endmethod
    endstruct
endlibrary
 
Level 21
Joined
Nov 14, 2008
Messages
3,256
Rough check.

Applies to all spells.

-Why libraries? Scopes are fine. (useless point anyway but whatever)

-why are effect globals and atktype/dmgtype not constant?

-You should set a local into GetEnumUnit() (as an example) in the onDamage method so you'll reduce the amount of calls.

-Why are you destroying groups? GroupUtils? You use TimerUtils anyway.

-in condition methods GetOwningPlayer(dat.Caster) --> GetTriggerPlayer()

Doesn't apply to all spells.

-Why are you using a dot system made in GUI? It's not hard to create your own and Dynasti made one in vJASS as well. Look it up.

-Why isn't dart struct private? Is it used by other spells besides poison darts?

Anyway I like these alot and see that you've put alot of effort into these projects! Great stuff.
 
Top