Dimensional Flux Collector v1
3500
ID:
306
Family ID:
Author:
cedi
Rarity:
unique
Element:
storm
Status:
Approved

Description:

Has got a direct link to the fifth dimension.
Dimensional Link
Creates a link between this tower and the target tower. This tower will now monitor any spell damage dealt by the linked tower to creeps within 2000 range of this tower. If the linked tower is sold, replaced or upgraded the link will dissolve.

AC_TYPE_NOAC_PLAYER_TOWER
 0, 800 range, 1s cooldown
Dimensional Distortion Field - Aura
Each second this tower attacks a creep within 800 range, dealing 25% of the linked tower's spell damage per second as energy damage to the target creep. This tower can only attack if a link exists for at least 10 seconds. Benefits from attackspeed bonuses.

Level Bonus:
+1% of spell dps as damage
Download

Toggle Triggers

Autocast

caster_art: AUTOCAST_cooldown: 1 AUTOCAST_numBuffsBeforeIdle: 0 AUTOCAST_isExtended: false AUTOCAST_autocastType: AC_TYPE_NOAC_PLAYER_TOWER AUTOCAST_manacost: 0 AUTOCAST_range: 800 AUTOCAST_buffType: 0 AUTOCAST_targetSelf: false AUTOCAST_targetType: TARGET_TYPE_PLAYER_TOWERS target_art: AUTOCAST_autoRange: 800
private function onAutocast takes Tower tower returns nothing
    local Tower T
    local Buff B
    
    set B = Event.getTarget().getBuffOfType( LINK )
    if B != 0 then
        //Target is linked to another one of these towers.
        //Destroy that link
        call B.removeBuff()
    endif
    
    //It should be impossible for this to create a double free as this can only be true if the
    //linked tower and the target aren't the same. Else the buff is destroyed before this
    //-> tower.userInt3 == 0 (buff cleanup)
    if tower.userInt3 != 0 then
        //already linked! Cancel first!
        set T = tower.userInt3
        set B = T.getBuffOfType( LINK )
        
        call B.removeBuff()
        
        //Reset dps //Done in the buff's oncleanup, to make sure link is broken in case of selling / up
        //set tower.userReal = 0.0
        //set tower.userInt2 = 1
    endif
    
    set tower.userInt3 = Event.getTarget()
    call LINK.apply( tower, Event.getTarget(), 0 )
endfunction

Header

    globals
        BuffType BT
        BuffType LINK
        MultiboardValues MB
        
        ProjectileType PT
        
        constant real AURA_RANGE = 2000.00
        
        hashtable TABLE = InitHashtable()
    endglobals
    
    function AddToTheList takes Tower T, Buff B returns nothing
        local integer i = LoadInteger( TABLE, B, 0 ) + 1
        call SaveInteger( TABLE, B, i, T )
        call SaveInteger( TABLE, B, 0, i )
        //In range -> count
        set T.userInt = T.userInt + 1
    endfunction
    
    function IsInTheList takes Tower T, Buff B returns integer
        local integer i = LoadInteger( TABLE, B, 0 )
        
        loop
            if LoadInteger( TABLE, B, i ) == T then
                return i
            endif
            set i = i - 1
            exitwhen i <= 0
        endloop
        
        return 0
    endfunction
    
    function RemoveFromTheList takes Tower T, Buff B returns nothing
        local integer fullcount = LoadInteger( TABLE, B, 0 )
        local integer pos = IsInTheList( T, B )
        
        if pos == 0 then
            //Tower not in the list
            return
        endif
        
        if fullcount == pos then
            //Last element
        else
            //Sorting!
            call SaveInteger( TABLE, B, pos, LoadInteger( TABLE, B, fullcount ) )
        endif
        
        //cleanup
        call RemoveSavedInteger( TABLE, B, fullcount )
        //Save new total
        call SaveInteger( TABLE, B, 0, fullcount - 1 )
        //No longer in range -> don't count
        set T.userInt = T.userInt - 1
    endfunction
    
    function LinkCreate takes Buff B returns nothing
        local Tower T = B.getCaster().userInt3
        local Tower C = B.getCaster()
        local Lightning l = Lightning.createFromPointToUnit( "DRAM", C.getX(), C.getY(), C.getZ() + 220, T )
        set B.userInt = l
    endfunction
    
    function LinkEnd takes Buff B returns nothing
        local Tower tower = B.getCaster()
        local Lightning l = B.userInt
        //Cleanup sfx
        call l.destroy()
        
        //Reset dps
        set tower.userReal = 0.0
        set tower.userInt2 = 1
        
        //clear Link value
        set tower.userInt3 = 0
    endfunction
    
    function BuffCheck takes Buff B returns nothing
        local unit c = B.getBuffedUnit().getUnit()
        local integer i = LoadInteger( TABLE, B, 0 )
        local Tower T
        
        if i <= 0 then
            //can happen, as the aura range != checking range.
            set c = null
            return
        endif
        
        loop
            set T = LoadInteger( TABLE, B, i )
            if not IsUnitInRange( c, T.getUnit(), AURA_RANGE ) then
                //Unit is no longer in range of this tower. Remove the tower from the list
                //Sorting and this shouldn't cause problems, as all sortet items are already
                //checked.
                call RemoveFromTheList( T, B )
            endif
            set i = i - 1
            exitwhen i <= 0 
        endloop
        set c = null
    endfunction
    
    function BuffCreate takes Buff B returns nothing
        //local Tower T = B.getCaster()
        //set T.userInt = T.userInt + 1
        
        //Save the origin
        call SaveInteger( TABLE, B, 0, 0 )
        //call SaveInteger( TABLE, B, 1, T )
    endfunction
    
    //Remove all items from the list
    function BuffEnd takes Buff B returns nothing
        local integer i = LoadInteger( TABLE, B, 0 )
        local Tower T
        
        loop
            set T = LoadInteger( TABLE, B, i )
            call RemoveFromTheList( T, B )
            set i = i - 1
            exitwhen i <= 0
        endloop
    endfunction
    
    function BuffTrigger takes Buff B returns nothing
        local Buff trig = Event.getTarget().getBuffOfType( LINK )
        local Tower T
        
        if Event.isSpellDamage() and trig != 0 then //Spelldamage and attacking tower == linked tower
            set T = trig.getCaster() //the linker
            if IsInTheList( T, B ) != 0 then
                //Only add the damage if the linker is on the list == in range
                set T.userReal = T.userReal + Event.damage //add damage to the linker
            endif
        endif
        
    endfunction
    
    function ProjHit takes Projectile P, Unit U returns nothing
        local Tower T = P.getCaster()
        call T.doCustomAttackDamage( U, T.userReal / T.userInt2 * ( 0.25 + T.getLevel() * 0.01 ), T.calcAttackMulticrit( 0, 0, 0 ), AttackType.ENERGY )
    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 BT = BuffType.createAuraEffectType( false )
        call BT.addEventOnCreate( BuffCreate )
        call BT.addEventOnCleanup( BuffEnd )
        call BT.addPeriodicEvent( BuffCheck, 1.0 )
        call BT.addEventOnDamaged( BuffTrigger, 1.0, 0.0 )
        call BT.setBuffIcon( '@@0@@' )
        
        set LINK = BuffType.create( -1, 0.0, true )
        call LINK.addEventOnCreate( LinkCreate )
        call LINK.addEventOnCleanup( LinkEnd )
        call LINK.setBuffIcon( '@@1@@' )
        
        set MB = MultiboardValues.create( 1 )
        call MB.setKey( 0, "DPS" )
        
        set PT = ProjectileType.createInterpolate( "Abilities\\Spells\\Undead\\OrbOfDeath\\OrbOfDeathMissile.mdl", 1000.0 )
        call PT.setEventOnInterpolationFinished( ProjHit )
    endfunction

On Tower Creation

function onCreate takes Tower tower returns nothing
    set tower.userReal = 0.0 //overall damage
    set tower.userReal2 = 0.0 //active?
    set tower.userInt = 0 //buffed creeps
    set tower.userInt2 = 1 //time
    set tower.userInt3 = 0 //Link Target
endfunction

On Tower Destruction

function onDestruct takes Tower tower returns nothing
    local Tower targ

    //Remove link on destroy of this tower
    if tower.userInt3 != 0 then
        //Target is linked
        set targ = tower.userInt3
        call targ.getBuffOfType( LINK ).removeBuff()
    endif
endfunction

On Tower Details

goldcost: 0
function onTowerDetails takes Tower tower returns MultiboardValues
    call MB.setValue( 0, formatFloat( tower.userReal / tower.userInt2 * ( 0.15 + tower.getLevel() * 0.006 ), 0 ) )
    return MB
endfunction

On Unit Comes In Range

UNITINRANGE_targetType: TARGET_TYPE_CREEPS UNITINRANGE_range: 2000
function onUnitInRange takes Tower tower returns nothing
    //Okay, new creep just came in range of this tower's aura - 1 (to make sure it has the buff)
    //So let's add it to the TABLE, as long as it isn't already added.
    local Creep C = Event.getTarget()
    local Buff B = C.getBuffOfType( BT )
    
    if B != 0 then
        //Buffed unit entered
        if IsInTheList( tower, B ) == 0 then
            //Not in the list
            call AddToTheList( tower, B )
        endif
    endif
endfunction

Periodic

PERIODIC_period: 1.0
function periodic takes Tower tower returns nothing
    local Iterate I
    local Unit U
    if tower.userInt3 == 0 then
        //NOT LINKED! Do nothing!
        return
    endif
    
    if tower.userReal <= 0.0 then
        //No dmg to deal! Do nothing!
        return
    endif
    
    if tower.userInt > 0 then //at least one unit in range
        set tower.userInt2 = tower.userInt2 + 1
        set tower.userReal2 = 1
        
        //Outsourced
        //At least 10 seconds connected? (counting starts at 1, so 10 seconds are 11)
        //if tower.userInt2 <= 10 then
        //    return
        //endif
        
        //ATTACK 
        //set I = Iterate.overUnitsInRangeOfCaster( tower, TARGET_CREEPS, 800.00 )
        //set U = I.nextRandom()
        
        //if U != 0 then
            //Target Found. Launch Projectile.
        //    call Projectile.createBezierInterpolationFromPointToUnit( PT, tower, 1.0, 1.0, tower.getX(), tower.getY(), tower.getZ(), U, 0.35, 0.0, 0.0, true )
        //    call I.destroy()
        //endif
    else
        //No unit in range, check if there was one in range during last tick
        if tower.userReal2 > 0 then
            set tower.userReal2 = -1
            set tower.userInt2 = tower.userInt2 + 1
        endif
    endif
endfunction

Periodic

PERIODIC_period: 1.0
function periodic takes Tower tower returns nothing
    local Iterate I
    local Unit U
    
    call Event.getCurrentPeriodicEvent().enableAdvanced( tower.getCurrentAttackspeed(), true )
    
    if tower.userInt3 == 0 then
        //NOT LINKED! Do nothing!
        return
    endif
    
    if tower.userReal <= 0.0 then
        //No dmg to deal! Do nothing!
        return
    endif
    
    if tower.userInt > 0 then //at least one unit in range
        //set tower.userInt2 = tower.userInt2 + 1
        //set tower.userReal2 = 1
        
        //Outsourced
        //At least 10 seconds connected? (counting starts at 1, so 10 seconds are 11)
        if tower.userInt2 <= 10 then
            return
        endif
        
        //ATTACK 
        set I = Iterate.overUnitsInRangeOfCaster( tower, TARGET_CREEPS, 800.00 )
        set U = I.nextRandom()
        
        if U != 0 then
            //Target Found. Launch Projectile.
            call Projectile.createBezierInterpolationFromPointToUnit( PT, tower, 1.0, 1.0, tower.getX(), tower.getY(), tower.getZ(), U, 0.35, 0.0, 0.0, true )
            call I.destroy()
        endif
    else
        //No unit in range, check if there was one in range during last tick
        //if tower.userReal2 > 0 then
        //    set tower.userReal2 = -1
        //    set tower.userInt2 = tower.userInt2 + 1
        //endif
    endif
endfunction

Tower Aura

AURA_auraEffect: BT AURA_power: 0 AURA_level: 0 AURA_auraRange: 2150.00 AURA_targetType: TARGET_TYPE_CREEPS AURA_levelAdd: 1 AURA_powerAdd: 1 AURA_targetSelf: false
Death Knight v1
3500
ID:
317
Family ID:
Author:
DaveMatthews
Rarity:
unique
Element:
darkness
Attack Type:
Decay
Attack Range:
875
Attack CD:
1.1
Damage:
2659-2659
Mana:
50
Mana regen:
0
Status:
Approved

Description:

Feeds on souls to unleash his full power.
Specials:
+2 mana/lvl
Will of the Undying
The death knight decreases the base attack damage of all towers in 200 range by 10% and loses 50% of his remaining mana to increase his base damage by 15% for each tower affected for 5 seconds. Only towers that cost at least 1300 gold are affected by this spell. 

Level Bonus:
+0.2% damage absorbed

AC_TYPE_OFFENSIVE_IMMEDIATE
 50, 900 range, 10s cooldown
Insatiable Hunger
On each attack, the death knight deals 0.25% bonus damage for each mana point he's currently missing and replenishes 1% of his maximum mana. He replenishes 5% of his maximum mana for each unit he kills. 

Level Bonus:
+0.01% damage per mana point
Withering Presence
Whenever a unit comes in 900 range of the death knight, it has a 15% chance to have its health regeneration reduced by 50% and to lose 5% of its current health every second for 4 seconds. Units affected by this spell grant 50% less experience and bounty on death. 

Level Bonus:
+0.4% chance 
+1% health regen reduction 
-1% experience and bounty reduction
Download

Toggle Triggers

Autocast

caster_art: Abilities\Spells\Other\HowlOfTerror\HowlCaster.mdl AUTOCAST_cooldown: 10 AUTOCAST_numBuffsBeforeIdle: 0 AUTOCAST_isExtended: false AUTOCAST_autocastType: AC_TYPE_OFFENSIVE_IMMEDIATE AUTOCAST_manacost: 50 AUTOCAST_range: 900 AUTOCAST_buffType: 0 AUTOCAST_targetSelf: false AUTOCAST_targetType: 0 target_art: AUTOCAST_autoRange: 900
private function onAutocast takes Tower tower returns nothing
    local integer numTowers = 0
    local integer level = tower.getLevel() 
    local Tower u
    local Iterate it = Iterate.overUnitsInRangeOfCaster(tower, TARGET_TOWERS, 200)
    local unit towerUnit = tower.getUnit()
    local real mana = GetUnitState(towerUnit, UNIT_STATE_MANA)
     
    call SetUnitState(towerUnit , UNIT_STATE_MANA, mana/2)
    loop
        set u = it.next()
        exitwhen u == 0
        if u != tower and u.getGoldcost() >= 1300 then
            set numTowers = numTowers + 1
            call dave_will_negative.apply(tower, u, (50 + level))
        endif
    endloop
    if numTowers > 0 then
        call dave_will_positive.apply(tower, tower, (75 + level) * numTowers)
    endif
    set towerUnit = null 
endfunction

Header

    globals
        BuffType dave_will_positive
        BuffType dave_will_negative
        BuffType dave_withering
    endglobals
    
    function OnWithering takes Buff b returns nothing
        local Unit buffed = b.getBuffedUnit()
        local Unit caster = b.getCaster()
        local unit u = buffed.getUnit()
        local real hp = GetWidgetLife(u)
        local real damage = hp * 0.05
    
        call SetWidgetLife(u, hp - damage)
        set u = null
    endfunction
      

    private function init takes nothing returns nothing
        local Modifier m = Modifier.create()
        local Modifier n = Modifier.create()
        local Modifier o = Modifier.create()
        
        set dave_will_positive = BuffType.create(5.0,0.0,true)
        call dave_will_positive.setBuffModifier(m)
        call m.addModification(MOD_DAMAGE_BASE_PERC,0.0,0.002)
        call dave_will_positive.setBuffIcon( '@@0@@' )
        
        set dave_will_negative = BuffType.create(5.0,0,false)
        call dave_will_negative.setBuffModifier(n)
        call n.addModification(MOD_DAMAGE_BASE_PERC,-0.0,-0.002)
        call dave_will_negative.setBuffIcon( '@@1@@' )
        
        set dave_withering = BuffType.create(4.0,0,false)
        call dave_withering.setBuffModifier(o)
        call o.addModification(MOD_HP_REGEN_PERC,-0.5,-0.1)
        call o.addModification(MOD_EXP_GRANTED,-0.5,0.01)
        call o.addModification(MOD_BOUNTY_GRANTED,-0.5,0.01)
        call dave_withering.addPeriodicEvent(EventHandler.OnWithering,1)
        call dave_withering.setBuffIcon( '@@2@@' )
    endfunction

On Damage

ONDAMAGE_chance: 1.0 ONDAMAGE_chanceLevelAdd: 0.0
function onDamage takes Tower tower returns nothing
    local unit towerUnit = tower.getUnit()
    local integer level = tower.getLevel()
    local real mana = GetUnitState(towerUnit,UNIT_STATE_MANA)
    local real maxMana = GetUnitState(towerUnit,UNIT_STATE_MAX_MANA)
     
    call SetUnitState(towerUnit , UNIT_STATE_MANA, mana+(maxMana*0.01))
    set Event.damage = Event.damage+(Event.damage*((maxMana-mana)*(0.0025+0.0001*level)))
    set towerUnit = null
endfunction

On Kill

function onKill takes Tower tower returns nothing
    local unit towerUnit = tower.getUnit()
    local real mana = GetUnitState(towerUnit, UNIT_STATE_MANA)
    local real maxMana = GetUnitState(towerUnit,UNIT_STATE_MAX_MANA)
     
    call SetUnitState(towerUnit , UNIT_STATE_MANA, mana+(maxMana*0.05))
    set towerUnit = null
endfunction

On Unit Comes In Range

UNITINRANGE_targetType: TARGET_TYPE_CREEPS UNITINRANGE_range: 900
function onUnitInRange takes Tower tower returns nothing
    local integer level = tower.getLevel()
    
    if tower.calcChance(0.15+level*0.004) then
       call dave_withering.apply(tower,Event.getTarget(),level)
    endif
endfunction
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

Description:

Unleashes mighty drakes against his enemies.
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
Ancient Jungle Stalker v1
3500
ID:
550
Family ID:
Author:
Boekie
Rarity:
rare
Element:
nature
Attack Type:
Physical
Attack Range:
850
Attack CD:
1.1
Damage:
2021-2120
Status:
Approved

Description:

This tower becomes enraged when it kills a unit and also gets stronger with every critical hit.
Specials:
20% crit chance (+0.5%/lvl)
Feral Aggression
On every critical hit this tower gains +0.4% bonus damage. This bonus is permanent and has a maximum of 250% bonus damage.
Bloodthirst
Whenever this tower kills a unit it becomes enraged, gaining +150% attackspeed for 5 seconds. Cannot retrigger while active!

Level Bonus:
+0.05 sec duration
+1% attackspeed
Download

Toggle Triggers

Header

    globals
        //@import
        BuffType boekie_rage_buff
        //@import
        MultiboardValues boekie_jungle_stalker_values
    endglobals
    
    //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    
    endfunction

On Damage

ONDAMAGE_chance: 1.0 ONDAMAGE_chanceLevelAdd: 0.0
function onDamage takes Tower tower returns nothing
    local real damageBonus

    if Event.isAttackDamageCritical() and tower.userReal <= 2.5 then 
        set tower.userReal = tower.userReal + 0.004
        call tower.modifyProperty(MOD_DAMAGE_ADD_PERC, 0.004)
    endif
endfunction

On Kill

function onKill takes Tower tower returns nothing
    local integer lvl = tower.getLevel() 
    if tower.getBuffOfType(boekie_rage_buff) == 0 then  
        call boekie_rage_buff.applyCustomTimed(tower, tower, 50+lvl, 5.0+0.05*lvl) 
    endif
endfunction

On Tower Creation

function onCreate takes Tower tower returns nothing
    local Tower preceding = Event.getPrecedingTower()  
    local real damageBonus 

    if(preceding.getFamily() == tower.getFamily()) then  
        set damageBonus = preceding.userReal 
        set tower.userReal = damageBonus 
        call tower.modifyProperty(MOD_DAMAGE_ADD_PERC, damageBonus)  
    else  
        set tower.userReal = 0.0 //Damage bonus  
    endif 
endfunction

On Tower Details

function onTowerDetails takes Tower tower returns MultiboardValues
    call boekie_jungle_stalker_values.setValue(0, formatPercent(tower.userReal, 1))
    return boekie_jungle_stalker_values
endfunction
Glaive Master v1
3600
ID:
435
Family ID:
Author:
Ashbringer
Rarity:
unique
Element:
iron
Attack Type:
Physical
Attack Range:
1000
Attack CD:
1.4
Damage:
1855-1855
Status:
Approved

Description:

Eviscerate them all, make them bleed.
Specials:
Bounce attack:
   2 targets
Glaivesaw:
Create a Glaivesaw at the target location. Glaivesaws deal 50% of attack damage as Lacerate damage to enemies within 150 range per second. Limit 3.

Level Bonus:
+1% damage
Glaive Storm
Hits have a 5% chance to throw an additional glaive at the target, dealing 50% of attack damage as Lacerate damage before returning to the tower. When the glaive returns, it bounces to a new random target within attack range. Maximum of 20 hits. 

Level Bonus:
+0.2% chance
+2% damage
Bounder
Attacks have a 15% chance to throw a glaive at one of your Glaivesaws. The glaive will bounce to another Glaivesaw, dealing 250% of attack damage as Lacerate damage to enemies it passes through.

Level Bonus:
+0.6% chance
+6% damage
Lacerate
This tower's attacks and abilities deal Lacerate damage. 50% of Lacerate damage is dealt immediately as Physical damage. 100% of the remaining damage is dealt as Decay damage over 5 seconds. If this effect is reapplied, any remaining damage will be added to the new duration. Damage over time is based on the target's movement speed, with faster movement increasing the damage dealt.

Level Bonus:
+1% damage over time
Download

Toggle Triggers

Header

    globals
        BuffType ashbringer_lacerate_buff
        ProjectileType ashbringer_storm_missile
        ProjectileType ashbringer_bounder_missile
    endglobals
    
    struct Machinations
        integer max
        Effect array e[3]
        boolean array b[3]
        real array x[3]
        real array y[3]
        integer array c[3]
    endstruct
    
    function ashbringer_machinations_setup  takes Tower tower returns nothing
        local Machinations ma = Machinations.create()
        local integer count = 0
        
        set tower.userInt = 0
        set tower.userReal2 = I2R(tower.getUID())
        set ma.max = 3 + 1
        
        loop
            set ma.e[count] = 0
            set ma.b[count] = false
            set ma.c[count] = 3 + 1
            set count = count + 1
            exitwhen count==3
        endloop
        set tower.userInt3 = ma
    endfunction
    
    function ashbringer_lacerate_damage takes Tower tower, Creep target, real damage, real crit returns nothing
        local Buff b
        local real damage_stack
        local real dot_inc = 1.0 + (tower.getLevel() * 0.01)
        local real dot_damage = damage * crit
        
        call tower.doAttackDamage(target, damage * 0.5, crit)
        set b = target.getBuffOfType(ashbringer_lacerate_buff)
        if b != 0 then
            set damage_stack = b.userReal + (dot_damage * 0.5 * dot_inc)
            set ashbringer_lacerate_buff.apply(tower, target, 0).userReal = damage_stack
        else
            set ashbringer_lacerate_buff.apply(tower, target, 0).userReal = (dot_damage * 0.5 * dot_inc)
        endif
    endfunction
    
    function ashbringer_lacerate_dot takes Buff b returns nothing
        local Tower tower = b.getCaster()
        local Creep target = b.getBuffedUnit()
        local real remaining = b.getRemainingDuration()
        local real damage = b.userReal / remaining
        local real damage_tick = damage
        local real movement_relative = GetUnitMoveSpeed(target.getUnit()) / 261
        
        if target.isStunned() then
            set damage_tick = 0
        else
            if remaining<1 then
                set damage = b.userReal
                set damage_tick = damage
            endif
        endif
        
        if damage_tick>0 then
            set b.userReal = b.userReal - damage
            call tower.doCustomAttackDamage(target, damage_tick, 1.0, AttackType.DECAY)
        endif
    endfunction
    
    function ashbringer_bounder_throw takes Tower tower returns nothing
        local Machinations ma = tower.userInt3
        local real damage = tower.getCurrentAttackDamageWithBonus() * (2.5 + (tower.getLevel() * 0.06))
        local integer random = GetRandomInt(0, ma.max)
        local integer bounces = 1
        local Projectile p
        
        if ma.max!=(3+1) then
            set p = Projectile.createLinearInterpolationFromPointToPoint(ashbringer_bounder_missile, tower, 0, 0, tower.getX(), tower.getY(), 110, ma.x[random], ma.y[random], 0, 0)
            set p.userInt = random
            set p.userInt2 = bounces
            set p.userReal = damage
        endif
    endfunction
    
    function ashbringer_bounder_bounce takes Projectile p, Creep target returns nothing
        local Tower tower = p.getCaster()
        local Machinations ma = tower.userInt3
        local Projectile n
        local integer closest = ma.c[p.userInt]
        
        if p.userInt2>0 and closest!=(3+1) then
            call p.avertDestruction()
            call p.startLinearInterpolationToPoint(ma.x[closest], ma.y[closest], 0, 0)
            set p.userInt = closest
            set p.userInt2 = p.userInt2-1
        endif
    endfunction
    
    function ashbringer_bounder_hit takes Projectile p, Unit target returns nothing
        local Tower tower = p.getCaster()
        call ashbringer_lacerate_damage(tower, target, p.userReal, tower.calcAttackMulticrit(0,0,0))
    endfunction
    
    function ashbringer_storm_throw takes Tower tower, Creep target returns nothing 
        local real damage = tower.getCurrentAttackDamageWithBonus() * (0.5 + (tower.getLevel() * 0.02))
        local Projectile p
        
        set p = Projectile.createBezierInterpolationFromUnitToUnit(ashbringer_storm_missile, tower, 1, 1, tower, target, 0, 0.3, 0.17, true)
        set p.userInt = 1
        set p.userInt2 = 20
        set p.userReal = damage
        set p.userReal2 = tower.getX()
        set p.userReal3 = tower.getY()
    endfunction
    
    function ashbringer_storm_bounce takes Projectile p, Creep target returns nothing 
        local Tower tower = p.getCaster()
        local Iterate i
        
        if p.userInt==1 then
            call p.avertDestruction()
            call ashbringer_lacerate_damage(tower, target, p.userReal, tower.calcAttackMulticrit(0,0,0))
            call p.startBezierInterpolationToPoint(p.userReal2, p.userReal3, 100, 0, 0.3, 0.17)
            set p.userInt = 0
        elseif p.userInt2>0 then
            set i = Iterate.overUnitsInRange(tower, TARGET_TYPE_CREEPS, p.userReal2, p.userReal3, 1000)
            set target = i.nextRandom()
            if target!=0 then
                call p.avertDestruction()
                call p.startBezierInterpolationToUnit(target, 0, 0.3, 0.17, true)
                set p.userInt = 1
                set p.userInt2 = p.userInt2 - 1
                call i.destroy()
            endif
        endif
    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  ashbringer_lacerate_buff = BuffType.create(5, 0, false)
        call ashbringer_lacerate_buff.setBuffIcon('@@1@@')
        call ashbringer_lacerate_buff.addPeriodicEvent(ashbringer_lacerate_dot, 1.0)
        
        set ashbringer_storm_missile = ProjectileType.createInterpolate("Abilities\\Weapons\\SentinelMissile\\SentinelMissile.mdl", 900)
        call ashbringer_storm_missile.setEventOnInterpolationFinished(ProjectileTargetEvent.ashbringer_storm_bounce)
        
        set ashbringer_bounder_missile = ProjectileType.createInterpolate("Abilities\\Weapons\\GlaiveMissile\\GlaiveMissile.mdl", 2000)
        call ashbringer_bounder_missile.enableCollision(ProjectileTargetEvent.ashbringer_bounder_hit, 100, TARGET_TYPE_CREEPS, false)
        call ashbringer_bounder_missile.setEventOnInterpolationFinished(ProjectileTargetEvent.ashbringer_bounder_bounce)
    endfunction

On Attack

ONATTACK_chance: 1.0 ONATTACK_chanceLevelAdd: 0.0
function onAttack takes Tower tower returns nothing
    local real bounder_chance = 0.15 + (tower.getLevel() * 0.006)
    
    if tower.calcChance(bounder_chance) then
        call ashbringer_bounder_throw(tower)
    endif
endfunction

On Damage

ONDAMAGE_chance: 1.0 ONDAMAGE_chanceLevelAdd: 0
function onDamage takes Tower tower returns nothing
    local Creep target = Event.getTarget()
    local real storm_chance = 0.05 + (tower.getLevel() * 0.002)
    
    call ashbringer_lacerate_damage(tower, target, tower.getCurrentAttackDamageWithBonus(), tower.calcAttackMulticrit(0,0,0))
    set Event.damage = 0
    
    if tower.calcChance(storm_chance) then
        call ashbringer_storm_throw(tower, target)
    endif
endfunction

On Spell Cast

function onSpellCast takes Tower tower returns nothing
    local Machinations ma = tower.userInt3
    local real target_x = GetSpellTargetX()
    local real target_y = GetSpellTargetY()
    local real dist1
    local real dist2 = 0
    local integer subcount
    local integer max_mach = 3
    local integer count = 0
    local integer sel = max_mach + 1
    local integer closest
    
    loop
        if ma.b[count]==false then
            set ma.b[count] = true
            set ma.e[count] = Effect.createAnimatedScaled("Abilities\\Weapons\\BloodElfSpellThiefMISSILE\\BloodElfSpellThiefMISSILE.mdl", target_x+20, target_y, 40.0, 0.0, 1.45)
            call ma.e[count].setAnimationSpeed(2.0)
            call ma.e[count].setScale(2.0)
            set ma.x[count] = target_x
            set ma.y[count] = target_y
            if count==0 then
                set ma.c[count] = sel
            elseif count==1 then
                set ma.c[count-1] = 1
                set ma.c[count] = 0
            else
                set ma.c[count] = sel
            endif
            set ma.max = count
            
            set sel = count
            set count = max_mach
        else
        endif
        set count = count + 1
        
        exitwhen count>=max_mach
    endloop
    
    if sel>max_mach then
        set count = 0
        call ma.e[0].destroy()
        loop
            if count<(max_mach-1) then
                set ma.b[count] = ma.b[count+1]
                set ma.e[count] = ma.e[count+1]
                set ma.x[count] = ma.x[count+1]
                set ma.y[count] = ma.y[count+1]
                set ma.c[count] = sel
            endif
            set count = count + 1
            
            exitwhen count==max_mach
        endloop
        
        set ma.b[max_mach-1] = true
        set ma.e[max_mach-1] = Effect.createAnimatedScaled("Abilities\\Weapons\\BloodElfSpellThiefMISSILE\\BloodElfSpellThiefMISSILE.mdl", target_x+20, target_y, 40.0, 0.0, 1.45)
        call ma.e[max_mach-1].setAnimationSpeed(2.0)
        call ma.e[max_mach-1].setScale(2.0)
        set ma.x[max_mach-1] = target_x
        set ma.y[max_mach-1] = target_y
        set ma.c[max_mach-1] = sel
        
        set sel = 0
    endif

    if ma.max>1 then
        set count = 0
        loop
            if ma.b[count]==true then
                set subcount = 0
                set closest = max_mach + 1
                set dist2 = 0
                loop
                    if ma.b[subcount]==true and count!=subcount then
                        set dist1 = SquareRoot(((ma.x[subcount]-ma.x[count]) * (ma.x[subcount]-ma.x[count])) + ((ma.y[subcount]-ma.y[count]) * (ma.y[subcount]-ma.y[count])))
                        
                        if dist2==0 then
                            set dist2 = dist1
                        endif
                        
                        if dist1<=dist2 and dist1>=50 then
                            set dist2 = dist1
                            set closest = subcount
                        endif
                    endif
                    set subcount = subcount + 1
                    
                    exitwhen subcount==max_mach
                endloop
                set ma.c[count] = closest
            endif
            set count = count + 1
            
            exitwhen count==max_mach
        endloop
    endif
    
    set tower.userInt3 = ma
endfunction

On Tower Creation

function onCreate takes Tower tower returns nothing
    call ashbringer_machinations_setup(tower)
endfunction

On Tower Destruction

function onDestruct takes Tower tower returns nothing
    local Machinations ma = tower.userInt3
    local integer max_mach = 3
    local integer count = max_mach
    
    loop
        set count = count - 1
        if ma.b[count] == true then
            call ma.e[count].destroy()
        endif
        
        exitwhen count==0
    endloop
endfunction

Periodic

PERIODIC_period: 1.0
function periodic takes Tower tower returns nothing
    local Machinations ma = tower.userInt3
    local Iterate i
    local integer count = 0
    local integer max_mach = 3
    local real damage = tower.getCurrentAttackDamageWithBonus() * (0.5 + (tower.getLevel() * 0.01))
    local Creep next
    
    loop
        if ma.b[count] == true then
            set i = Iterate.overUnitsInRange(tower, TARGET_TYPE_CREEPS, ma.x[count], ma.y[count], 150)
            set next = i.next()
            loop
                exitwhen next == 0
                call Effect.createSimpleOnUnit("Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl", next, "origin").setLifetime(2.0)
                call ashbringer_lacerate_damage(tower, next, damage, tower.calcAttackMulticrit(0,0,0))
                set next = i.next()
            endloop
            //call i.destroy()
        endif
        
        set count = count + 1
        exitwhen count==max_mach
    endloop
endfunction
Ebonfrost Crystal v1
3600
ID:
437
Family ID:
Author:
Ashbringer
Rarity:
unique
Element:
ice
Attack Type:
Elemental
Attack Range:
1000
Attack CD:
1.6
Damage:
1960-1960
Mana:
400
Mana regen:
0
Status:
Approved

Description:

A pristine crystal atop a pillar of black frost.
Shattering Barrage
Spends all mana to encase the target in ice, stunning it and increasing damage taken by 100% for up to [mana / 150] seconds. All icicles are then fired at the target. Duration is reduced by 75% on Bosses, to a minimum of 2 seconds.

Level Bonus:
-1 mana divisor

AC_TYPE_OFFENSIVE_UNIT
 300, 1000 range, 30s cooldown
Icicles
Attacks have a 15% chance and Icy Bombardments have a 5% chance to create an icicle on hit, which is stored and waits to be fired. Stored icicles passively increase attack damage by 5% and mana regen by 0.5 mana per second each. Maximum of 5 icicles. At maximum icicles, any more icicles created are instantly fired at the target. Each icicle deals 3000 Frostburn damage on hit and permanently increases the damage dealt by future icicles by this tower by 2%.

Level Bonus:
+0.4% chance on attack
+0.1% chance on Icy Bombardment
+80 damage
+1 max icicle every 5 levels
Icy Bombardment
Attacks have a 15% chance to fire a projectile at a random point within 150 range of the attacked creep that deals 25% of current attack damage as Frostburn damage in 200 AoE splash. Each additional projectile has a 30% chance to fire another, up to a maximum of 4 per attack.

Level Bonus:
+0.4% initial chance
+0.4% additional chance
+0.6% damage
Frostburn
This tower's attacks and abilities deal Frostburn damage. 50% of the damage is dealt immediately as attack damage. 100% of the remaining damage is dealt as spell damage over 5 seconds. If this effect is reapplied, any remaining damage will be added to the new duration.

Level Bonus:
+1% damage over time
Download

Toggle Triggers

Autocast

AUTOCAST_cooldown: 30 AUTOCAST_autoRange: 750 AUTOCAST_manacost: 300 AUTOCAST_range: 1000 AUTOCAST_targetType: 0 AUTOCAST_numBuffsBeforeIdle: 0 caster_art: target_art: AUTOCAST_autocastType: AC_TYPE_OFFENSIVE_UNIT AUTOCAST_buffType: 0 AUTOCAST_isExtended: true AUTOCAST_targetSelf: false
private function onAutocast takes Tower tower returns nothing
    local Creep target = Event.getTarget()
    local real towermana = GetUnitState( tower.getUnit(), UNIT_STATE_MANA)
    local real duration = towermana / (150 - tower.getLevel())
        
    if target.getSize()==SIZE_BOSS then 
        set duration = duration * 0.25
        if duration<2.0 then
            set duration = 2.0
        endif
    endif
    call ashbringer_shatter_buff.applyCustomTimed(tower, target, tower.getLevel(), duration)
    call tower.subtractMana(towermana, true)
endfunction

Header

    globals
        BuffType ashbringer_frostburn_buff
        BuffType ashbringer_shatter_buff
        ProjectileType ashbringer_breath_missile
        BuffType ashbringer_icicle_buff
        ProjectileType ashbringer_icicle_prop
        ProjectileType ashbringer_icicle_missile
    endglobals
    
    struct Icicles
        Projectile array p[10]
        Effect array e[10]
        boolean array t[10]
        real array x[10]
        real array y[10]
    endstruct
    
    function ashbringer_icicles_setup  takes Tower tower returns nothing
        local Icicles ic = Icicles.create()
        local integer count = 0
        set tower.userInt = 0
        set tower.userInt2 = 5 //starting max
        set tower.userReal = 0
        set tower.userReal2 = I2R(tower.getUID())
        
        loop
            set ic.e[count] = 0
            set ic.t[count] = false
            set count = count + 1
            exitwhen count==10
        endloop
        set tower.userInt3 = ic
    endfunction
    
    function ashbringer_icicle_fire takes Tower tower, Creep target returns nothing
        call Projectile.createFromPointToUnit(ashbringer_icicle_missile, tower, 0, 0, tower.getX(), tower.getY(), 200, target, true, false, false).setScale(0.7)
        set tower.userReal = tower.userReal + 1
    endfunction
    
    function ashbringer_icicle_store takes Tower tower returns nothing
        local integer num = tower.userInt
        local real tower_x
        local real tower_y
        local real angle
        local real target_x
        local real target_y
        local Projectile p
        local Icicles ic = tower.userInt3
        
        //safeguard against remnant icicles, find open icicle slot
        if ic.t[num]==true then
            set num = 0
            loop
                set num = num + 1
                exitwhen num==tower.userInt2 or ic.t[num-1]!=true
            endloop
        endif
        if num<tower.userInt2 then
            set angle = 360 / tower.userInt2 * num
            set tower_x = tower.getX()
            set tower_y = tower.getY()
            set target_x = tower_x + 100 * Cos(Deg2Rad(angle))
            set target_y = tower_y + 100 * Sin(Deg2Rad(angle))
            set p = Projectile.createLinearInterpolationFromPointToPoint(ashbringer_icicle_prop, tower, 1.0, 0.0, tower_x, tower_y, 200, target_x, target_y, 200, 0.0)
            call p.setScale(0.7)
            set p.userReal = target_x
            set p.userReal2 = target_y
            set p.userReal3 = angle
            set p.userInt = num
            set ic.p[num] = p
            set ic.x[num] = p.userReal
            set ic.y[num] = p.userReal2
            set ic.t[num] = true
            set tower.userInt = tower.userInt + 1
            call ashbringer_icicle_buff.apply(tower, tower, tower.userInt)
        endif
    endfunction
    
    function ashbringer_icicle_effect takes Projectile p, Unit target returns nothing
        local Tower tower = p.getCaster()
        local Icicles ic = tower.userInt3
        
        if ic.e[p.userInt]!=0 then
            call ic.e[p.userInt].destroy()
        endif
        if ic.t[p.userInt]==true and tower.getUID()!=0 and tower.getUID()==R2I(tower.userReal2) then
            set ic.e[p.userInt] = Effect.createScaled("Abilities\\Spells\\Other\\FrostBolt\\FrostBoltMissile.mdl", p.userReal, p.userReal2, 200, p.userReal3, 0.7)
            call ic.e[p.userInt].noDeathAnimation()
        endif
    endfunction
    
    function ashbringer_icicle_create takes Tower tower, Creep target returns nothing
        if tower.userInt<tower.userInt2 then
            call ashbringer_icicle_store(tower) //stores the icicle
        else
            call ashbringer_icicle_fire(tower, target) //fires on immediately
        endif
    endfunction
    
    function ashbringer_frostburn_damage takes Tower tower, Creep target, real damage returns nothing
        local Buff b
        local real damage_stack
        local real dot_inc = 1.0 + (tower.getLevel() * 0.01)
        local integer limit = 25 + tower.getLevel()
        
        call tower.doAttackDamage(target, damage * 0.5, tower.calcAttackMulticrit(0, 0, 0))
        set b = target.getBuffOfType(ashbringer_frostburn_buff)
        if b != 0 then
            set damage_stack = b.userReal + (damage * 0.5 * dot_inc)
            set ashbringer_frostburn_buff.apply(tower, target, 0).userReal = damage_stack
        else
            set ashbringer_frostburn_buff.apply(tower, target, 0).userReal = (damage * 0.5 * dot_inc)
        endif
    endfunction
    
    function ashbringer_frostburn_dot takes Buff b returns nothing
        local Tower tower = b.getCaster()
        local Creep target = b.getBuffedUnit()
        local real remaining = b.getRemainingDuration()
        local real damage_tick = b.userReal / remaining
        
        if remaining<1 then
            set damage_tick = b.userReal
        endif
        if damage_tick>0 then
            set b.userReal = b.userReal - damage_tick
            call tower.doSpellDamage(target, damage_tick, tower.calcSpellCritNoBonus())
        endif
    endfunction
    
    public function ashbringer_icicle_hit takes Projectile p, Creep target returns nothing 
        local Tower tower = p.getCaster()

        call ashbringer_frostburn_damage(tower, target, (3000 + (tower.getLevel() * 80)) * (1.0 + (tower.userReal * 0.02)))
    endfunction
    
    public function ashbringer_icicle_fireall takes Tower tower, Creep target returns nothing
        local Icicles ic = tower.userInt3
        local integer count = tower.userInt2
        local Projectile icicle
        local Buff b
        
        set tower.userInt = tower.userInt2 //set to max so any created during this time are fired instantly
        loop
            set count = count - 1
            if ic.t[count]==true then
                set icicle = Projectile.createFromPointToUnit(ashbringer_icicle_missile, tower, 0, 0, ic.x[count], ic.y[count], 200, target, true, false, false)
                set icicle.speed = 1400 - (count * 70)
                call icicle.setScale(0.7)
                set tower.userReal = tower.userReal + 1
                set ic.t[count] = false
            endif
            call ic.p[count].destroy()
            if ic.e[count]!=0 then
                call ic.e[count].destroy()
            endif
            set ic.p[count] = 0
            set ic.e[count] = 0
            exitwhen count==0
        endloop
        set tower.userInt = 0
        set b = tower.getBuffOfType(ashbringer_icicle_buff)
        if b != 0 then
            call b.removeBuff()
        endif
    endfunction
    
    function ashbringer_breath_barrage takes Tower tower, real chance, Creep target returns nothing
        local integer shots = 0
        local real target_x = target.getX()
        local real target_y = target.getY()
        local integer UID = target.getUID()
        local Projectile p
        local real random_angle
        local real random_distance
        local real launch_x
        local real launch_y
        
        loop
            set random_angle = GetRandomReal(0, 360)
            set random_distance = GetRandomReal(0, 150)
            set launch_x = target_x + random_distance * Cos(Deg2Rad(random_angle))
            set launch_y = target_y + random_distance * Sin(Deg2Rad(random_angle))
            set p = Projectile.createLinearInterpolationFromPointToPoint(ashbringer_breath_missile, tower, 0, 0, tower.getX(), tower.getY(), 200, launch_x, launch_y, 0, 0.2)
            set p.userReal = launch_x
            set p.userReal2 = launch_y
            set shots = shots + 1
            exitwhen tower.calcChance(chance) == false or shots>=4
        endloop
    endfunction
    
    function ashbringer_breath_hit takes Projectile p returns nothing
        local Tower tower = p.getCaster()
        local Iterate i = Iterate.overUnitsInRange(tower, TARGET_TYPE_CREEPS, p.userReal, p.userReal2, 200)
        local Creep next = i.next()
        local real damage = tower.getCurrentAttackDamageWithBonus() * (0.25 + (tower.getLevel() * 0.006))
        local real icicle_chance = 0.05 + (tower.getLevel() * 0.001)
        
        loop
            exitwhen next == 0
            call ashbringer_frostburn_damage(tower, next, damage)
            if tower.calcChance(icicle_chance) then
                call ashbringer_icicle_create(tower, next)
            endif
            set next = i.next()
        endloop
    endfunction
    
    function ashbringer_shatter_oncreate takes Buff b returns nothing
        local Tower tower = b.getCaster()
        local Creep target = b.getBuffedUnit()
        
        call cb_stun.applyOnlyTimed(tower, target, b.getRemainingDuration())
        call ashbringer_icicle_fireall(tower, target)
    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 ashbringer_icicle_modifier = Modifier.create()
        local Modifier ashbringer_shatter_modifier = Modifier.create()
        
        set  ashbringer_frostburn_buff = BuffType.create(5, 0, false)
        call ashbringer_frostburn_buff.setBuffIcon('@@0@@')
        call ashbringer_frostburn_buff.addPeriodicEvent(ashbringer_frostburn_dot, 1.0)
        
        set  ashbringer_shatter_buff = BuffType.create(5, 0, false)
        call ashbringer_shatter_buff.setBuffIcon('@@1@@')
        call ashbringer_shatter_modifier.addModification(MOD_ATK_DAMAGE_RECEIVED, 0, 1.0)
        call ashbringer_shatter_modifier.addModification(MOD_SPELL_DAMAGE_RECEIVED, 0, 1.0)
        call ashbringer_shatter_buff.setBuffModifier(ashbringer_shatter_modifier)
        call ashbringer_shatter_buff.addEventOnCreate(ashbringer_shatter_oncreate)
        
        set ashbringer_icicle_buff = BuffType.create(-1.0, 0, true)
        call ashbringer_icicle_buff.setBuffIcon('@@2@@')
        call ashbringer_icicle_modifier.addModification(MOD_DAMAGE_ADD_PERC, 0.0, 0.05)
        call ashbringer_icicle_modifier.addModification(MOD_MANA_REGEN, 0.0, 0.5)
        call ashbringer_icicle_buff.setBuffModifier(ashbringer_icicle_modifier)
        
        set ashbringer_breath_missile = ProjectileType.create("Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl", 5, 1650) 
        call ashbringer_breath_missile.setEventOnCleanup(ProjectileEvent.ashbringer_breath_hit)
        
        set ashbringer_icicle_prop = ProjectileType.createInterpolate("Abilities\\Spells\\Other\\FrostBolt\\FrostBoltMissile.mdl", 200)
        call ashbringer_icicle_prop.setEventOnInterpolationFinished(ashbringer_icicle_effect)
        call ashbringer_icicle_prop.disableExplodeOnExpiration()
        
        set ashbringer_icicle_missile = ProjectileType.create("Abilities\\Spells\\Other\\FrostBolt\\FrostBoltMissile.mdl", 5, 1400)
        call ashbringer_icicle_missile.enableHoming(ProjectileTargetEvent.ashbringer_icicle_hit, 0)
    endfunction

On Attack

ONATTACK_chance: 0.15 ONATTACK_chanceLevelAdd: 0.004
function onAttack takes Tower tower returns nothing
    call ashbringer_breath_barrage(tower, 0.3 + (tower.getLevel() * 0.004), Event.getTarget())
endfunction

On Damage

ONDAMAGE_chance: 1.0 ONDAMAGE_chanceLevelAdd: 0.0
function onDamage takes Tower tower returns nothing
    local Creep target = Event.getTarget()
    local real damage = Event.damage
    local real icicle_chance = 0.15 + (tower.getLevel() * 0.004)
    
    call ashbringer_frostburn_damage(tower, target, damage)
    set Event.damage = 0
    if tower.calcChance(icicle_chance) then
        call ashbringer_icicle_create(tower, Event.getTarget())
    endif
endfunction

On Level Up

function onLevelUp takes Tower tower returns nothing
    local integer prev_max = tower.userInt2
    local Icicles ic = tower.userInt3
    local Buff b
    local integer count = 0
    
    set tower.userInt2 = 5 + (tower.getLevel() / 5)
    
    //cleanup ones over the limit on delevel
    if tower.userInt2<prev_max then
        set count = tower.userInt2
        loop
            if ic.t[count]==true then
                call ic.p[count].destroy()
                if ic.e[count]!=0 then
                    call ic.e[count].destroy()
                endif
                set ic.t[count] = false
            endif
            set count = count + 1
            exitwhen count==10
        endloop
    endif
endfunction

On Tower Creation

function onCreate takes Tower tower returns nothing
    call ashbringer_icicles_setup(tower)
endfunction

On Tower Destruction

function onDestruct takes Tower tower returns nothing
    local Icicles ic = tower.userInt3
    local integer count = 0
    local Buff b
    
    loop
        if ic.t[count]==true then
            call ic.p[count].destroy()
            if ic.e[count]!=0 then
                call ic.e[count].destroy()
            endif
            set ic.t[count] = false
        endif
        set count = count + 1
        exitwhen count==10
    endloop
    call ic.destroy()
    set b = tower.getBuffOfType(ashbringer_icicle_buff)
    if b != 0 then
        call b.removeBuff()
    endif
endfunction
Living Volcano v1
3600
ID:
468
Family ID:
Author:
Kricz
Rarity:
unique
Element:
fire
Attack Type:
Decay
Attack Range:
1100
Attack CD:
1.8
Damage:
1771-1771
Status:
Approved

Description:

An ancient volcano that has lived for thousands of years. The heat radiating from its lava can be felt from kilometers away.
Specials:
+45% dmg to nature (+2%/lvl)
+7.5% damage/lvl
+1.5% spell damage/lvl
Heat Stroke
Whenever a creep dies while under the effect of Heat Aura, there is a 40% chance that it will explode, dealing 4500 damage in 300 AoE. 

Level Bonus: 
+100 damage
Lava Attack
Has a 25% chance on attack to throw a burning lava ball towards the target's location, dealing 3500 damage to creeps in 300 AoE. 

Level Bonus: 
+5 AoE 
+100 damage
Heat Aura - Aura
Burns every enemy in 700 range, making them lose 3% of their current life every second.
Download

Toggle Triggers

Header

    globals 
        ProjectileType Kricz_LV_M
        BuffType Kricz_LV_HA
    endglobals
    
    function ragingHeatDamage takes Buff b returns nothing 
        local Creep creep = b.getBuffedUnit()  
        local Tower tower = b.getCaster()
        local unit u = creep.getUnit() 
        local real life = GetWidgetLife(u)
        local real dmg = life * 0.03 * tower.getDamageToCategory(creep.getCategory())
        //Gex meant it is okay so...
        if life < 2. then
            call tower.killInstantly(creep)
        else
            call SetWidgetLife(u, life - dmg)
        endif
        set u = null
    endfunction 
    
    function heatStroke takes Buff b returns nothing
        local Tower tower = b.getCaster()
        local Creep creep = b.getBuffedUnit()
        if tower.calcChance(0.4) then
            call SFXAtUnit("Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl",creep.getUnit())
            call tower.doSpellDamageAoEUnit(creep, 300, 4500 + tower.getLevel() * 100, tower.calcSpellCritNoBonus(), 0.33)
        endif
    endfunction
    
    function LavaAttackMissileEnd takes Projectile p returns nothing
        local Unit c = p.getCaster()        
        call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", p.x, p.y))
        call c.doSpellDamageAoE(p.x, p.y, p.userReal, p.userReal2, c.calcSpellCritNoBonus(), 0.25)             
    endfunction 
    
    private function init takes nothing returns nothing
        local Modifier HAM = Modifier.create() 
        set Kricz_LV_M = ProjectileType.create("Abilities\\Weapons\\BallsOfFireMissile\\BallsOfFireMissile.mdl", 1.5, 650)
        call Kricz_LV_M.setEventOnCleanup(ProjectileEvent.LavaAttackMissileEnd)
        
        set Kricz_LV_HA = BuffType.createAuraEffectType(false) 
        call Kricz_LV_HA.setBuffModifier(HAM)
        call Kricz_LV_HA.addPeriodicEvent(EventHandler.ragingHeatDamage, 1.0) 
        call Kricz_LV_HA.addEventOnDeath(EventHandler.heatStroke) 
        call Kricz_LV_HA.setStackingGroup("KRICZ_LV_DMG_AURA") 
        call Kricz_LV_HA.setBuffIcon('@@0@@') 
    endfunction 

On Attack

ONATTACK_chance: 0.25 ONATTACK_chanceLevelAdd: 0.0
function onAttack takes Tower tower returns nothing
    local Unit u = Event.getTarget()
    local integer lvl = tower.getLevel()
    local real AoE = 300 + 5 * lvl
    local real dmg = 3500. + lvl * 100 
    local Projectile p

    set p = Projectile.createLinearInterpolationFromUnitToPoint(Kricz_LV_M, tower, 1., tower.calcSpellCritNoBonus(), tower, u.getX(), u.getY(), 0., 0.45)
    set p.userReal = AoE
    set p.userReal2 = dmg
endfunction

Tower Aura

AURA_auraEffect: Kricz_LV_HA AURA_power: 1 AURA_level: 0 AURA_auraRange: 700 AURA_targetType: TARGET_TYPE_CREEPS AURA_levelAdd: 1 AURA_powerAdd: 1 AURA_targetSelf: false