Vol'jin the Witch Doctor v1
4600
ID:
114
Family ID:
Author:
SirCoqaLot.
Rarity:
unique
Element:
astral
Attack Type:
Elemental
Attack Range:
800
Attack CD:
2
Damage:
4756-4756
Abil. Factor:
0.375
Status:
Approved

Description:

"Try out my Voodoo maaan."                              credits to der_kleine_Tomy

Latest Upload Comment:

Restored from 1.10
Specials:
+3% attackspeed/lvl
+8% damage/lvl
Maledict
Vol'jin jinxes all units in 800 range around him. Targets caught by the jinx are dealt 15% of the damage they received as spell damage after 8 seconds. Maledict stacks, with each stack adding 3.5% additional damage. If Maledict is purged it deals double damage. This ability is unaffected by Buff Duration. 

Level Bonus:
+0.14% damage per stack
Serpent Ward
Vol'jin has an 18% chance on attack to summon 1 of 2 Serpent Wards to assist him. Each ward lasts 6 seconds modified by this tower's buff duration, deals 20% of Vol'jins attack damage and has Vol'jins current attackspeed at cast. Each Ward attacks a random target in 800 range and has a 35% chance to stack 'Maledict' on attack. Wards can not be resummoned and their duration cannot be refreshed. 

Level Bonus:
+0.2% attackdamage
+0.1 seconds duration
+0.28% chance to summon a ward
+1 maximum ward at level 15 and 25
Purify
Whenever Vol ' jin deals damage he purges all buffs and debuffs from his target, increasing his damage dealt on that attack by 12% for each purged effect. This ability has a 4 second cooldown.

Level Bonus:
-0.04 seconds cooldown
+0.16% damage per purged effect
Download

Toggle Triggers

Autocast

AUTOCAST_cooldown: 5 AUTOCAST_autoRange: 800 AUTOCAST_manacost: 30 AUTOCAST_range: 800 AUTOCAST_targetType: 0 AUTOCAST_numBuffsBeforeIdle: 0 caster_art: target_art: AUTOCAST_autocastType: AC_TYPE_OFFENSIVE_IMMEDIATE AUTOCAST_buffType: 0 AUTOCAST_isExtended: true AUTOCAST_targetSelf: false
private function onAutocast takes Tower tower returns nothing
    local Iterate it = Iterate.overUnitsInRangeOfUnit(tower,TARGET_CREEPS,tower,800)
    local Unit u
    loop
        set u = it.next()
        exitwhen u == 0
        call ApplyMaledict(tower,u,true)
    endloop
endfunction

Header

    globals
        BuffType sir_voljin_debuff
        ProjectileType sir_voljin_projectile
        hashtable voljin_hashtable
        // 0 = Ward 1
        // 1 = Duration
        // 2/3 = Position(x/y)
        // 4 = Ward 2
        // ...
    endglobals
    
    function damageEvent takes Buff b returns nothing
        set b.userReal = b.userReal + Event.damage
    endfunction
    
    function expireEvent takes Buff b returns nothing
        call b.getCaster().doSpellDamage(b.getBuffedUnit(),(0.15+(0.035+0.0014*b.getCaster().getLevel())*b.getLevel())*R2I(b.userReal),b.getCaster().calcSpellCritNoBonus())
    endfunction
    
    function purgeEvent takes Buff b returns nothing
        call b.getCaster().doSpellDamage(b.getBuffedUnit(),(0.3+(0.07+0.0028*b.getCaster().getLevel())*b.getLevel())*R2I(b.userReal),b.getCaster().calcSpellCritNoBonus())
    endfunction
    
    function ApplyMaledict takes Tower caster, Unit target, boolean B returns nothing
        local Buff b = target.getBuffOfType(sir_voljin_debuff)
        local real duration = caster.getProp_BuffDuration()
        if B == true and b == 0 then
            set sir_voljin_debuff.applyAdvanced(caster, target,1, 0, 8.0/duration).userReal = 0.0
        elseif (b != 0 and B == false and caster.calcChance(0.35)) or (b != 0 and B == true) then
            call sir_voljin_debuff.applyAdvanced(caster, target, b.getLevel() + 1, 0, 8.0/duration)
        endif
    endfunction
    
    function voljin_hit takes Projectile p, Unit hit returns nothing
        local Tower tower = p.getCaster()
        call tower.doAttackDamage(hit,tower.getCurrentAttackDamageWithBonus() * (0.2+tower.getLevel()*0.002),tower.calcAttackMulticrit(0,0,0))
        call ApplyMaledict(tower,hit,false)
    endfunction
    
    
    //Do not remove or rename this function!
    //Put your initialization tasks here, this function will be called on map init
    private function init takes nothing returns nothing
        set voljin_hashtable = InitHashtable()
        
        set sir_voljin_debuff = BuffType.create(0,0,false)
        call sir_voljin_debuff.setBuffIcon('@@0@@')
        call sir_voljin_debuff.addEventOnDamaged(damageEvent,1,0)
        call sir_voljin_debuff.setEventOnExpire(expireEvent)
        call sir_voljin_debuff.setEventOnPurge(purgeEvent)
    
        set sir_voljin_projectile=ProjectileType.create("Abilities\\Weapons\\SerpentWardMissile\\SerpentWardMissile.mdl",10.0,1200.0)
        call sir_voljin_projectile.enableHoming(ProjectileTargetEvent.voljin_hit,0.0)
    endfunction

On Attack

ONATTACK_chance: 0.18 ONATTACK_chanceLevelAdd: 0.0028
function onAttack takes Tower tower returns nothing
    local integer level = tower.getLevel()
    local unit towerUnit = tower.getUnit()
    local real attackspeed = tower.getCurrentAttackspeed()
    local PeriodicEvent periodicEvent = tower.userInt
    local real towerUnitZ = GetUnitFlyHeight(towerUnit)
    local integer counter = 0
    local integer maxWards = 2
    local Effect e
    local real duration
    local real x
    local real y
    
    if level == 25 then
        set maxWards = 4
    elseif level >= 15 then
        set maxWards = 3
    endif
    
    loop
        // Check whether all wards already exist, if not create one
        if not HaveSavedInteger(voljin_hashtable, tower, counter) then
            set x = LoadReal(voljin_hashtable, tower, counter + 2)
            set y = LoadReal(voljin_hashtable, tower, counter + 3)
            set e = Effect.createAnimated("units\\orc\\SerpentWard\\SerpentWard.mdl", x, y, towerUnitZ - 20, -(45.0 + 90.0 * (counter / 4)))
            call e.setScale(0.4)
            set duration = (6.0+tower.getLevel()*0.1) * tower.getProp_BuffDuration()
            
            call SaveInteger(voljin_hashtable, tower, counter, e) // Save the effect
            call SaveReal(voljin_hashtable, tower, counter + 1, duration) // Save the duration
            
            set tower.userInt2 = tower.userInt2 + 1 // Save the amount of wards
            // The first ward has been created => Start the Periodic Event
            if tower.userInt2 == 1 then
                call periodicEvent.enableAdvanced(attackspeed, false)
                set tower.userReal = attackspeed // Save the periodic interval
            endif
            
            exitwhen true // Exit
        endif
        set counter = counter + 4 // Move to the next ward
        exitwhen counter > (maxWards * 4 - 4)
    endloop
    
    
    set towerUnit = null
endfunction

On Damage

ONDAMAGE_chance: 1.0 ONDAMAGE_chanceLevelAdd: 0.0
function onDamage takes Tower tower returns nothing
    local Unit creep = Event.getTarget()
    local real damage = Event.damage
    local integer numPurgedBuffs = 0
    
    // Remove buffs (positive and negative buffs) and count them
    if tower.userInt3 <= Game.getGameTime() then
        set tower.userInt3 = Game.getGameTime()+100-tower.getLevel() // adding the cd
        loop
            exitwhen not (creep.purgeBuff(true) or creep.purgeBuff(false))
            set numPurgedBuffs = numPurgedBuffs + 1
        endloop
        
        set damage = damage*(1+numPurgedBuffs*(0.12+tower.getLevel()*0.0016)) // 12% damage 
        set Event.damage = damage
        if numPurgedBuffs != 0 then
            call tower.getOwner().displaySmallFloatingText(I2S(R2I(damage)),tower,255,150,255,0)
        endif
    endif
endfunction

On Tower Creation

function onCreate takes Tower tower returns nothing
    local real towerX = tower.getX()
    local real towerY = tower.getY()
    
    set tower.userInt = 0 // Contains the Periodic Event
    set tower.userInt2 = 0 // Stores the amount of wards
    set tower.userReal = 0 // Stores the periodic interval
    set tower.userInt3 = Game.getGameTime()-100 // stores the cooldown of purify
    // Ward 1
    call SaveReal(voljin_hashtable, tower,  2, towerX + 38)
    call SaveReal(voljin_hashtable, tower,  3, towerY - 53)
    // Ward 2
    call SaveReal(voljin_hashtable, tower,  6, towerX - 43)
    call SaveReal(voljin_hashtable, tower,  7, towerY - 45)
    // Ward 3
    call SaveReal(voljin_hashtable, tower,  10, towerX - 33)
    call SaveReal(voljin_hashtable, tower,  11, towerY + 38)
    // Ward 4
    call SaveReal(voljin_hashtable, tower, 14, towerX + 35)
    call SaveReal(voljin_hashtable, tower, 15, towerY + 38)
endfunction

On Tower Destruction

function onDestruct takes Tower tower returns nothing
    local integer counter = 0
    loop
        if HaveSavedInteger(voljin_hashtable, tower, counter) then
            call Effect(LoadInteger(voljin_hashtable, tower, counter)).destroy()
        endif
        set counter = counter + 4
        exitwhen counter > 12
    endloop
    call FlushChildHashtable(voljin_hashtable, tower)
endfunction

Periodic

PERIODIC_period: 0.1
function periodic takes Tower tower returns nothing
    local Effect e
    local Unit u
    local Projectile p
    local PeriodicEvent periodicEvent = tower.userInt
    local Iterate it
    local Unit array targets
    local integer numTargets = 0
    local integer counter = 0
    local real duration
    local real facing
    local real x
    local real y
    
    // If it's the first time this event fires
    if periodicEvent == 0 then
        set tower.userInt = Event.getCurrentPeriodicEvent() // Save the event
        call Event.getCurrentPeriodicEvent().disable() // Disable it
        return
    endif
 
    // Get all targets in range
    set it = Iterate.overUnitsInRangeOfCaster(tower,TARGET_CREEPS,800)
    loop
        set u = it.next()
        exitwhen u == 0
        set targets[numTargets] = u
        set numTargets = numTargets + 1
    endloop
    
    loop
        // Is there a ward ?
        if HaveSavedInteger(voljin_hashtable, tower, counter) then
            set e = LoadInteger(voljin_hashtable, tower, counter) // Load ward effect
            set u = targets[GetRandomInt(0, numTargets - 1)] // Get a random target
            set duration = LoadReal(voljin_hashtable, tower, counter + 1) - tower.userReal // Set duration to duration - periodic interval
            if duration > 0 then // Is there duration remaining?
                if u != 0 then // Is there are unit which can be attacked ?
                    // Load position
                    set x = LoadReal(voljin_hashtable, tower, counter + 2)
                    set y = LoadReal(voljin_hashtable, tower, counter + 3)
                    // Calculate the angle between the ward and the target
                    set facing = Atan2(GetUnitY(u.getUnit()) - y, GetUnitX(u.getUnit()) - x) * bj_RADTODEG
                    call e.setFacing(facing) // Set facing
                    call e.setAnimation("attack") // Play attack animation
                    // Shoot prohectile
                    set p = Projectile.createFromPointToUnit(sir_voljin_projectile, tower, 1.0, 1.0, x, y, 147.0, u, true, false, false)
                    call p.setScale(0.4)
                    call e.queueAnimation("stand") // Play the stand animation again
                endif
                // Save the remaining duration
                call SaveReal(voljin_hashtable, tower, counter + 1, duration)
            else // No more duration
                // Remove the ward effect from the hashtable
                call RemoveSavedInteger(voljin_hashtable, tower, counter)
                call e.destroy() // Destroy the ward
                set tower.userInt2 = tower.userInt2 - 1 // Decrease the ward counter
            endif
        endif
        set counter = counter + 4 // Next ward
        // Up to 4 wards with each taking 4 storage places in the hashtable starting at 0
        // => 4 wards * 4 places - 4
        exitwhen counter > (4 * 4 - 4)
    endloop
    // Disable the event
    call periodicEvent.disable()
    // Are there any wards?
    if tower.userInt2 > 0 then
        // Activate the event
        set tower.userReal = tower.getCurrentAttackspeed()
        call periodicEvent.enableAdvanced(tower.getCurrentAttackspeed() ,false)
    endif
endfunction