Saw your "Blaze," tower submission, and thought it was interesting. Could be a good replacement for the failed Hail/Comet Tower (Meteor Spell). Basically just a multi-shot tower with a nice twist, and I think that could work well. I've posted the most recent version of the code I could find here, although if you have more recent by all means. What I am asking for is: -Update the spell to work with the updated systems in the map (most recent file has been uploaded to the directory) -Optimize code if possible/needed -Make it use the DDS instead of unit is attacked trigger (which is abusable) -Greater configuration options, such as # of balls What a nice thing to stumble upon, the search is off for Hail/Comet Tower. scope Blaze //******************************************************************************** ********** //* //* Blaze //* //* //* A neat ability to use on a tower, which fires when units with the ability attack. //* //* Requires: //* - My caster system, implemented correctly into your map //* - This trigger copied to your map //* //******************************************************************************** ********** globals //config options: private constant integer abil_id = 'A001' //abil rawcode private constant real int = .025 //timer interval for effect movement private constant string attach_sfx = "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl" //effect model private constant real damage = 25. //damage done private constant real speed = 15. //missile speed private constant real range = 1000. //range for missiles to check for targets private constant boolean new_target = true //whether missiles can get a new target if their original dies in route private constant real cooldown = .5 //theoretical cooldown between attacks wanted, at a minimum //******************************************************************************** ********** //DON"T TOUCH PAST THIS POINT, UNLESS YOU PAIN FOR DEATH! //needed globals private timer Tball = CreateTimer() private integer Total1 = 0 private integer Total2 = 0 private Blaze_data1 array structArray1 private Blaze_data2 array structArray2 private unit U = null private group G = CreateGroup() endglobals //angle between units private function ABU takes unit a, unit b returns real return bj_RADTODEG * Atan2(GetUnitY(b) - GetUnitY(a), GetUnitX(b) - GetUnitX(a)) endfunction //distance between units private function DBU takes unit a, unit b returns real return SquareRoot(Pow(GetUnitX(b) - GetUnitX(a), 2) + Pow(GetUnitY(b)-GetUnitY(a),2)) endfunction //filter for missiles private function Filt takes nothing returns boolean return GetWidgetLife(GetFilterUnit())>.405 and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(U))==true endfunction //needed struct 2 struct Blaze_data2 unit ball = null unit targ = null effect sfx = null real height = 280. //init struct method Start takes unit ball, effect sfx returns nothing call GroupClear(G) set .ball = ball set .sfx = sfx set U = .ball //grab first target call GroupEnumUnitsInRange(G,GetUnitX(.ball),GetUnitY(.ball),range,Condition(function Filt)) set .targ = GroupPickRandomUnit(G) endmethod //move missile towards target method Effects takes nothing returns nothing local real ang = ABU(.ball,.targ) local real x = GetUnitX(.ball) + speed * Cos(ang * bj_DEGTORAD) local real y = GetUnitY(.ball) + speed * Sin(ang * bj_DEGTORAD) call SetUnitPosition(.ball,x,y) call SetUnitFacing(.ball,ang) set .height = .height - 10. call SetUnitFlyHeight(.ball,.height,0.0) endmethod //update globals method Update takes integer i returns nothing set structArray2[i] = structArray2[Total2] set Total2 = Total2 - 1 endmethod //end struct method onDestroy takes nothing returns nothing //damage target, destroy attached effect, recyle caster if .targ!=null then call UnitDamageTarget(.ball,.targ,damage,false,false,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_FI RE,null) endif call DestroyEffect(.sfx) call EndCaster(.ball,0) endmethod endstruct //needed struct 1 struct Blaze_data1 integer runs = 0 unit tower = null unit array ball[5] effect array sfx[5] real array ang[5] //initiate all needed struct data method Start takes unit tower, unit targ returns nothing local integer i = 1 local real x = GetUnitX(tower) local real x2 local real y = GetUnitY(tower) local real y2 local player p = GetOwningPlayer(tower) //loop from 1-5, create balls, attach effects, store angles loop exitwhen i>5 set x2 = x + 150. * Cos((i*72) * bj_DEGTORAD) set y2 = y + 150. * Sin((i*72) * bj_DEGTORAD) set .ball[i] = GetCaster(p,x2,y2,0) set .sfx[i] = AddSpecialEffectTarget(attach_sfx,.ball[i],"origin") set .ang[i] = i*72 set i = i + 1 endloop //store tower and target set .tower = tower endmethod //effects for each run, update angle, move ball, update fly height method Effects takes nothing returns nothing local integer i = 1 local real height = .runs * 7. local real distance = 150.-(.runs*3.75) local real x local real y loop exitwhen i>5 set .ang[i] = .ang[i] + 5. set x = GetUnitX(.tower) + distance * Cos(.ang[i] * bj_DEGTORAD) set y = GetUnitY(.tower) + distance * Sin(.ang[i] * bj_DEGTORAD) call SetUnitPosition(.ball[i],x,y) call SetUnitFlyHeight(.ball[i],height,0.0) set i = i + 1 endloop endmethod //update globals method Update takes integer i returns nothing set structArray1[i] = structArray1[Total1] set Total1 = Total1 - 1 endmethod //when our struct is destroyed, loop through balls and remove, effects and destroy method onDestroy takes nothing returns nothing local integer i = 1 local Blaze_data2 dat //tower is dead, end if GetWidgetLife(.tower)<.405 then loop exitwhen i>5 call DestroyEffect(.sfx[i]) call EndCaster(.ball[i],0) set i = i + 1 endloop else //tower is not dead, add missiles to new struct, and start that loop exitwhen i>5 set dat = Blaze_data2.create() call dat.Start(.ball[i],.sfx[i]) set Total2 = Total2 + 1 set structArray2[Total2] = dat set i = i + 1 endloop endif endmethod endstruct //filter for attackers function Trig_Blaze_Conditions takes nothing returns boolean return GetUnitAbilityLevel(GetAttacker(),abil_id)>0 and GetTableBoolean(I2S(H2I(GetAttacker()))+"Blaze","cooldown")==false endfunction //movement for missiles private function Movement takes nothing returns nothing local integer i = 1 local Blaze_data1 dat1 local Blaze_data2 dat2 loop //loop through all current structs 1 exitwhen i > Total1 set dat1 = structArray1[i] //update our runs total set dat1.runs = dat1.runs + 1 //effects are over, remove struct and clean up if dat1.runs>40 or GetWidgetLife(dat1.tower)<.405 then call dat1.destroy() call dat1.Update(i) set i = i - 1 else //runs are not over, continue with effects call dat1.Effects() endif set i = i + 1 endloop set i = 1 loop //loop through all current structs 2 exitwhen i > Total2 set dat2 = structArray2[i] //target is nothing, or is dead if dat2.targ==null or GetWidgetLife(dat2.targ)<.405 then //if the missile can get another target, try if new_target then call GroupClear(G) set U = dat2.ball call GroupEnumUnitsInRange(G,GetUnitX(dat2.ball),GetUnitY(dat2.ball),range,Condition( function Filt)) set dat2.targ = GroupPickRandomUnit(G) //no new target available if dat2.targ==null then call dat2.destroy() call dat2.Update(i) endif //so it runs this missile again if there is a new target, or for regular reasons set i = i + 1 else call dat2.destroy() call dat2.Update(i) set i = i - 1 endif //unit is close enough to damage, remove struct and clean up elseif DBU(dat2.ball,dat2.targ)<speed then call dat2.destroy() call dat2.Update(i) set i = i - 1 else //runs are not over, continue with effects call dat2.Effects() endif set i = i + 1 endloop //no more active structs, pause timer if Total1==0 and Total2==0 then call PauseTimer(Tball) endif endfunction //reset cooldown so this can fire again function Blaze_Clear takes nothing returns nothing local unit u = U //wait a bit, reset cooldown call TriggerSleepAction(cooldown) call ClearTable(I2S(H2I(u))+"Blaze") set u = null endfunction //init for missiles function Trig_Blaze_Actions takes nothing returns nothing local unit tower = GetAttacker() local unit targ = GetTriggerUnit() local Blaze_data1 dat = Blaze_data1.create() local string s = I2S(H2I(tower))+"Blaze" //init struct data, add it to array, start timer in not already done so if Total1==0 and Total2==0 then call TimerStart(Tball,int,true,function Movement) endif call dat.Start(tower,targ) set Total1 = Total1 + 1 set structArray1[Total1] = dat //store our tower to our global, reset its cooldown in the given function after a short wait set U = tower call SetTableBoolean(s,"cooldown",true) call ExecuteFunc("Blaze_Clear") set tower = null set targ = null endfunction endscope //=========================================================================== function InitTrig_Blaze takes nothing returns nothing set gg_trg_Blaze = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( gg_trg_Blaze, EVENT_PLAYER_UNIT_ATTACKED ) call TriggerAddCondition( gg_trg_Blaze, Condition( function Trig_Blaze_Conditions ) ) call TriggerAddAction( gg_trg_Blaze, function Trig_Blaze_Actions ) endfunction