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