Drake Whisperer v2
3500
|
ID: 426
Family ID:
Author: Ely
Rarity: unique
Element: astral
Attack Type: Elemental
Attack Range: 1000
Attack CD: 1.9
Damage: 3109-3138
Status: Approved
|
Specials:
+15% dmg to air (+0.4%/lvl)
Versatile
Every time this tower deals spell damage through its abilities, it increases its dps by 1.5% of the spell damage dealt. Lasts 2.5 seconds and stacks. Maximum bonus of [200 x (current wave)]. Level Bonus: +0.04% damage
Unleash
On attack, the Drake Whisperer has a 12.5% chance to unleash a bronze drake towards its target, dealing 1250 spell damage to a random creep in front of itself in 600 range every 0.2 seconds. Lasts 2 seconds. Level Bonus: +40 spell damage +0.3% chance
Feed the Drakes
Every 1.5 seconds, the Drake Whisperer feeds a nearby corpse to one of his drakes and unleashes it to a random target in 1000 range. If there is no target, the drake will attack on the next feeding, with a maximum of 5 fed drakes. Each corpse has a 15% chance to feed 2 drakes. The Blue Drake deals 6000 spell damage in 125 AoE and slows by 25% for 3 seconds. The Red Drake deals 200% of the tower's attack damage and stuns for 3 seconds. The Green Drake deals 5000 spell damage and spreads Versatile's current dps bonus to towers in 175 range for 2.5 seconds. Level Bonus: +0.4% double feed chance Blue Drake : +150 spell damage Red Drake : +8% damage Green Drake : +0.04 seconds duration |
Download
Toggle Triggers Header globals
BuffType versatileBuff
BuffType blueDrakeBuff
ProjectileType blueDrake
ProjectileType redDrake
ProjectileType greenDrake
ProjectileType bronzeDrake
ProjectileType bronzeDrakeAttack
constant integer BLUE = 0
constant integer GREEN = 1
constant integer RED = 2
// Drakeling status
constant integer IDLE = 0
constant integer ATTACKING = 1
constant integer COMING_BACK = 2
endglobals
struct Vec3
real x
real y
real z
endstruct
struct Drakelings
Projectile array d[3]
Vec3 array startPos[3]
endstruct
function allDrakesBusy takes Drakelings d returns boolean
return d.d[0].userInt != IDLE and d.d[1].userInt != IDLE and d.d[2].userInt != IDLE
endfunction
function launchDrakeling takes Tower t, integer which, Unit u returns nothing
local Drakelings d = t.userInt2
set d.d[which].speed = 600
call d.d[which].startBezierInterpolationToUnit(u, 0.15, 0.15, 0.17, true)
set d.d[which].userInt = ATTACKING
set t.userInt = t.userInt - 1
endfunction
function launchRandomDrakeling takes Tower t, Unit u returns nothing
local integer i = GetRandomInt(0, 2)
local Drakelings d = t.userInt2
loop
if d.d[i].userInt == IDLE then
call launchDrakeling(t, i, u)
return
endif
set i = ModuloInteger(i + 1, 3)
endloop
endfunction
function feeding takes Tower tower returns nothing
local Iterate it = Iterate.overUnitsInRangeOfCaster(tower, TARGET_TYPE_CREEPS, 1000)
local Unit u
local integer random
local Projectile p
local Drakelings d = tower.userInt2
local Effect e
local Iterate itCorpse
local unit corpse
local integer maxFedDrakes static constant = 5
// userInt = number of fed drakes, 5 max
if tower.userInt < maxFedDrakes then
set itCorpse = Iterate.overCorpsesInRange(tower, tower.getX(), tower.getY(), 1000)
set corpse = itCorpse.nextCorpse()
if corpse != null then
call ShowUnit(corpse, false)
set e = Effect.createScaled("Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl", tower.getX()+10, tower.getY(), tower.getZ() - 120, 0, 0.15)
call e.setLifetime(0.8)
if tower.calcChance(15/100.0 + (0.4/100.0)*tower.getLevel()) then
set tower.userInt = tower.userInt + 2
else
set tower.userInt = tower.userInt + 1
endif
if tower.userInt > maxFedDrakes then
set tower.userInt = maxFedDrakes
endif
set corpse = null
call itCorpse.destroy()
endif
endif
loop
if tower.userInt <= 0 or allDrakesBusy(d) then
call it.destroy()
return
endif
set u = it.nextRandom()
exitwhen u == 0
// Only red drakes deal physical, so unleash only them vs immune
if u.isImmune() then
if d.d[RED].userInt == IDLE then
call launchDrakeling(tower, RED, u)
endif
else
call launchRandomDrakeling(tower, u)
endif
endloop
endfunction
function refreshBuff takes Tower tower, real damage returns nothing
local Buff b = tower.getBuffOfType(versatileBuff)
local real powerup
local real maxDamage = 200*tower.getOwner().getTeam().getLevel()
if damage <= 0 then
return
endif
set powerup = damage*(1.5/100.0 + (0.04/100.0)*tower.getLevel())
if b != 0 then
set powerup = b.getPower() + powerup
if powerup > maxDamage then
set powerup = maxDamage
endif
call b.setPower(R2I(powerup))
call b.refreshDuration()
else
if powerup > maxDamage then
set powerup = maxDamage
endif
call versatileBuff.applyCustomPower(tower, tower, 1, R2I(powerup))
endif
endfunction
function spreadBuff takes Tower tower returns nothing
local Iterate it
local Buff b = tower.getBuffOfType(versatileBuff)
local Tower target
if b == 0 then
return
endif
set it = Iterate.overUnitsInRangeOfCaster(tower, TARGET_TYPE_TOWERS, 175)
loop
set target = it.next()
exitwhen target == 0
if target.getUnitType() != tower.getUnitType() then
call versatileBuff.applyAdvanced(tower, target, 1, b.getPower(), 2.5 + 0.04*tower.getLevel())
endif
endloop
endfunction
function blueDrakeHit takes Projectile p, Unit target returns nothing
local Tower tower = p.getCaster()
local real damage = tower.getOverallDamage()
local Iterate it
local Unit u
local Effect e
set it = Iterate.overUnitsInRange(tower, TARGET_TYPE_CREEPS, p.x, p.y, 125)
if it.count() == 0 then
call it.destroy()
return
endif
set e = Effect.createScaled("Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl", p.x, p.y, p.z, 0, 0.2)
call e.setLifetime(2.0)
loop
set u = it.next()
exitwhen u == 0
call blueDrakeBuff.apply(tower, u, 1)
call tower.doSpellDamage(u, 6000 + 150*tower.getLevel(), tower.calcSpellCritNoBonus())
endloop
set damage = tower.getOverallDamage() - damage
call refreshBuff(tower, damage)
endfunction
function greenDrakeHit takes Projectile p, Unit target returns nothing
local Tower tower = p.getCaster()
local real damage = tower.getOverallDamage()
if target == 0 then
call spreadBuff(tower)
return
endif
call tower.doSpellDamage(target, 5000, tower.calcSpellCritNoBonus())
set damage = tower.getOverallDamage() - damage
call refreshBuff(tower, damage)
call spreadBuff(tower)
endfunction
function redDrakeHit takes Projectile p, Unit target returns nothing
local Tower tower = p.getCaster()
if target == 0 then
return
endif
call cb_stun.applyOnlyTimed(tower, target, 3)
call tower.doAttackDamage(target, tower.getCurrentAttackDamageWithBonus()*(200/100.0 + (8/100.0)*tower.getLevel()), tower.calcAttackCritNoBonus())
endfunction
function sendDrakelingHome takes Projectile p returns nothing
local Drakelings d = p.getCaster().userInt2
local integer which = p.userInt2
set d.d[which].speed = 600
call d.d[which].startBezierInterpolationToPoint(d.startPos[which].x, d.startPos[which].y, d.startPos[which].z, 0.15, 0.15, 0.17)
set d.d[which].userInt = COMING_BACK
endfunction
function onDrakelingEndInterpol takes Projectile p, Unit target returns nothing
local integer which = p.userInt2
call p.avertDestruction()
if p.userInt == COMING_BACK then
// Will be used to reset the drake, otherwise the code in Projectile messes with our position right after this event handler
call p.enablePeriodic(1)
set p.remainingLifetime = 999999
return
endif
if which == RED then
call redDrakeHit(p, target)
elseif which == BLUE then
call blueDrakeHit(p, target)
else
call greenDrakeHit(p, target)
endif
call sendDrakelingHome(p)
endfunction
function bronzeDrakeTick takes Projectile p returns nothing
local Tower tower = p.getCaster()
local Iterate it
local Unit u
local Projectile atkProj
local real startX
local real startY
local real angleDiff
if p.getAge() > 2 then
call p.color(255, 255, 255, 255 - R2I(((p.getAge() - 2) / (3 - 2))*255))
return
endif
set it = Iterate.overUnitsInRange(tower, TARGET_TYPE_CREEPS, p.x, p.y, 600)
loop
set u = it.nextRandom()
exitwhen u == 0
if not u.isImmune() then
// Test if the target is in a 90° cone in front of the drake
set angleDiff = Atan2(u.getY() - p.y, u.getX() - p.x)*bj_RADTODEG - p.direction
if angleDiff <= -310 or angleDiff >= 310 or (angleDiff >= -50 and angleDiff <= 50) then
set startX = p.x + Cos(p.direction*bj_DEGTORAD) * 100
set startY = p.y + Sin(p.direction*bj_DEGTORAD) * 100
set atkProj = Projectile.createLinearInterpolationFromPointToUnit(bronzeDrakeAttack, tower, 0, 0, startX, startY, p.z + 20, u, 0.30, true)
call atkProj.setScale(0.55)
call it.destroy()
return
endif
endif
endloop
endfunction
function onBronzeDrakeHit takes Projectile p, Unit target returns nothing
local Tower tower = p.getCaster()
local real damage = tower.getOverallDamage()
if target == 0 then
return
endif
call tower.doSpellDamage(target, 1250 + 40*tower.getLevel(), tower.calcSpellCritNoBonus())
set damage = tower.getOverallDamage() - damage
call refreshBuff(tower, damage)
endfunction
// Hackish way of resetting the projectile and making it still, facing the tower
function resetPosition takes Projectile p returns nothing
local Tower t = p.getCaster()
local Drakelings d = t.userInt2
local integer which = p.userInt2
local real finalX
local real finalY
call p.disablePeriodic()
set p.x = d.startPos[which].x
set p.y = d.startPos[which].y
set p.z = d.startPos[which].z
set p.speed = 0
set p.userInt = IDLE
set finalX = p.x + (t.getX() - p.x)*10
set finalY = p.y + (t.getY() - p.y)*10
call p.aimAtPoint(finalX, finalY, p.z, false, 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
local Modifier versatileModifier = Modifier.create()
local Modifier blueDrakeModifier = Modifier.create()
call versatileModifier.addModification(MOD_DPS_ADD, 0.00, 1.00)
set versatileBuff = BuffType.create(2.5, 0.00, true)
call versatileBuff.setBuffModifier(versatileModifier)
call versatileBuff.setBuffIcon('@@0@@')
call blueDrakeModifier.addModification(MOD_MOVESPEED, -1*(25/100.0), 0)
set blueDrakeBuff = BuffType.create(3, 0.00, true)
call blueDrakeBuff.setBuffModifier(blueDrakeModifier)
call blueDrakeBuff.setBuffIcon('@@1@@')
set blueDrake = ProjectileType.create("Units\\Creeps\\AzureDragon\\AzureDragon.mdl", 999999, 0)
call blueDrake.disableExplodeOnHit()
call blueDrake.disableExplodeOnExpiration()
call blueDrake.setEventOnInterpolationFinished(onDrakelingEndInterpol)
call blueDrake.enablePeriodic(resetPosition, 0.1)
set redDrake = ProjectileType.create("Units\\Creeps\\RedDragon\\RedDragon.mdl", 999999, 0)
call redDrake.disableExplodeOnHit()
call redDrake.disableExplodeOnExpiration()
call redDrake.setEventOnInterpolationFinished(onDrakelingEndInterpol)
call redDrake.enablePeriodic(resetPosition, 0.1)
set greenDrake = ProjectileType.create("Units\\Creeps\\GreenDragon\\GreenDragon.mdl", 999999, 0)
call greenDrake.disableExplodeOnHit()
call greenDrake.disableExplodeOnExpiration()
call greenDrake.setEventOnInterpolationFinished(onDrakelingEndInterpol)
call greenDrake.enablePeriodic(resetPosition, 0.1)
set bronzeDrake = ProjectileType.create("Units\\creeps\\BronzeDragon\\BronzeDragon.mdl", 3, 350.0)
call bronzeDrake.disableExplodeOnHit()
call bronzeDrake.disableExplodeOnExpiration()
call bronzeDrake.enablePeriodic(bronzeDrakeTick, 0.2)
set bronzeDrakeAttack = ProjectileType.create("Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl", 2.5, 900.0)
call bronzeDrakeAttack.setEventOnInterpolationFinished(onBronzeDrakeHit)
endfunction
On Attack
ONATTACK_chance: 0.125
ONATTACK_chanceLevelAdd: 0.003
function onAttack takes Tower tower returns nothing
local integer i = GetRandomInt(0, 1)
local Projectile p
local Unit u = Event.getTarget()
local real finalX = tower.getX() + (u.getX() - tower.getX())*6
local real finalY = tower.getY() + (u.getY() - tower.getY())*6
set p = Projectile.createFromUnitToPoint(bronzeDrake, tower, 0, 0, tower, finalX, finalY, tower.getZ(), true, false)
call p.setScale(0.60)
endfunction
On Tower Creation function onCreate takes Tower tower returns nothing
local Drakelings d = Drakelings.create()
set d.d[0] = Projectile.create(blueDrake, tower, 0, 0, tower.getX() + 36, tower.getY() - 30, tower.getZ() - 30, 120)
set d.d[1] = Projectile.create(greenDrake, tower, 0, 0, tower.getX() - 50, tower.getY() - 13, tower.getZ() - 30, 10)
set d.d[2] = Projectile.create(redDrake, tower, 0, 0, tower.getX() + 27, tower.getY() + 59, tower.getZ() - 30, 250)
call d.d[0].disablePeriodic()
call d.d[1].disablePeriodic()
call d.d[2].disablePeriodic()
set d.d[0].userInt = IDLE
set d.d[1].userInt = IDLE
set d.d[2].userInt = IDLE
set d.d[0].userInt2 = 0
set d.d[1].userInt2 = 1
set d.d[2].userInt2 = 2
set d.startPos[0] = Vec3.create()
set d.startPos[0].x = tower.getX() + 36
set d.startPos[0].y = tower.getY() - 30
set d.startPos[0].z = tower.getZ() - 30
set d.startPos[1] = Vec3.create()
set d.startPos[1].x = tower.getX() - 50
set d.startPos[1].y = tower.getY() - 13
set d.startPos[1].z = tower.getZ() - 30
set d.startPos[2] = Vec3.create()
set d.startPos[2].x = tower.getX() + 27
set d.startPos[2].y = tower.getY() + 59
set d.startPos[2].z = tower.getZ() - 30
call d.d[0].setScale(0.25)
call d.d[1].setScale(0.25)
call d.d[2].setScale(0.25)
set tower.userInt = 0
set tower.userInt2 = d
endfunction
On Tower Destruction function onDestruct takes Tower tower returns nothing
local Drakelings d = tower.userInt2
local integer i = 0
loop
call d.d[i].destroy()
call d.startPos[i].destroy()
set i = i + 1
exitwhen i == 3
endloop
call d.destroy()
endfunction
Periodic
PERIODIC_period: 1.5
function periodic takes Tower tower returns nothing
call feeding(tower)
endfunction
|
Description: