/*
* Chain Bolt spell v1.3b by jim7777
*
*
* Copy the Chain Bolt(Thor) and ChainLightningBolt abilities
* Copy the libraries listed below then copy this trigger into your map
*
* Summons a hammer towards the target, dealing damage and stunning it then bounces to the nearest enemy
*
* Requires:
* GetClosestWidget (Spinnaker)
* TimerUtils (Vexorian)
* RegisterPlayerUnitEvent (Magtheridon96)
* SpellEffectEvent (Bribe)
********************************************************************************************************/
scope ChainBolt
globals
private constant integer ABILITY_ID = 'A001' // ability id of Chain Bolt (Thor) ability
private constant integer UNIT_ID = 'h001' // unit id of ChainLightningBolt unit
private constant integer STUN_ID = 'A000' //ability id of ChainLightningBolt ability. Eyecandy and stun purposes
private constant real INTERVAL = 0.03 //interval of movement of the hammer, better leave this alone
private constant real SPEED = 25 //how fast should the hammer move every INTERVAL seconds, better leave this alone
private constant real DETECTOR = 80 //range to detect if we will damage/stun the target, this should be a nice value
private constant real RADIUS = 800 //range to detect possible targets when bouncing the hammer. Change this to your liking
private constant integer MAX_BOUNCE = 4 //maximum number the hammer will bounce including the target
private constant boolean BOUNCE_BACK = false //should the hammer bounce back? If it is true, it will only look for the nearest unit where the hammer last striked
private constant string ORDER_STR = "thunderbolt" //order string of the STUN_ID, only change this if you aren't using Storm Bolt as base ability
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL //attack type of damage to be dealt
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC // damage type of damage to be dealt
endglobals
//=== set the damage dealt here
private function GetDmg takes real lvl returns real
return lvl*25
endfunction
//============== END OF CONFIGURABLES TOUCH THE CODES BELOW IF YOU KNOW WHAT YOU ARE DOING! ==========
private struct CLightning
unit caster
unit target
unit bolt
real dmg
player owner
integer bounce
group stack = null
private static thistype tmpDat
static method Filt takes nothing returns boolean
return tmpDat.target != GetFilterUnit() and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(tmpDat.caster)) and IsUnitVisible(GetFilterUnit(),GetOwningPlayer(tmpDat.caster)) and not IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) and not IsUnitType(GetFilterUnit(),UNIT_TYPE_MAGIC_IMMUNE) and GetFilterUnit() != tmpDat.target and not IsUnitInGroup(GetFilterUnit(),tmpDat.stack)
endmethod
static method ReturnHammer takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype dat = GetTimerData(t)
local real ux = GetUnitX(dat.bolt)
local real uy = GetUnitY(dat.bolt)
local real tx = GetUnitX(dat.caster)
local real ty = GetUnitY(dat.caster)
local real dx = tx - ux
local real dy = ty - uy
local real x
local real y
local real angle
if SquareRoot(dx * dx + dy * dy) > DETECTOR then
set angle = Atan2(dy, dx)
set x = ux + SPEED * Cos(angle)
set y = uy + SPEED * Sin(angle)
call SetUnitX(dat.bolt,x)
call SetUnitY(dat.bolt,y)
call SetUnitFacing(dat.bolt,angle*bj_RADTODEG)
else
static if not BOUNCE_BACK then
call DestroyGroup(dat.stack)
endif
call RemoveUnit(dat.bolt)
call ReleaseTimer(t)
call dat.destroy()
endif
set t = null
endmethod
static method OnLoop takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype dat = GetTimerData(t)
local real ux = GetUnitX(dat.bolt)
local real uy = GetUnitY(dat.bolt)
local real tx = GetUnitX(dat.target)
local real ty = GetUnitY(dat.target)
local real dx = tx - ux
local real dy = ty - uy
local real x
local real y
local real angle
if not IsUnitType(dat.target,UNIT_TYPE_DEAD) and null != dat.target then
if SquareRoot(dx * dx + dy * dy) > DETECTOR then
set angle = Atan2(dy, dx)
set x = ux + SPEED * Cos(angle)
set y = uy + SPEED * Sin(angle)
call SetUnitX(dat.bolt,x)
call SetUnitY(dat.bolt,y)
call SetUnitFacing(dat.bolt,angle*bj_RADTODEG)
else
if IssueTargetOrder(dat.bolt,ORDER_STR,dat.target) then
call UnitDamageTarget(dat.caster,dat.target,dat.dmg,false,false,ATTACK_TYPE,DAMAGE_TYPE,null)
endif
if dat.bounce < MAX_BOUNCE then
set dat.bounce = dat.bounce + 1
set tmpDat = dat
set dat.target = GetClosestUnitInRange(ux,uy,RADIUS,Filter(function thistype.Filt))
if dat.target == null then
call PauseTimer(t)
call TimerStart(t,INTERVAL,true,function thistype.ReturnHammer)
else
static if not BOUNCE_BACK then
call GroupAddUnit(dat.stack,dat.target)
endif
endif
endif
endif
elseif dat.bounce < MAX_BOUNCE then
set dat.bounce = dat.bounce + 1
set tmpDat = dat
set dat.target = GetClosestUnitInRange(ux,uy,RADIUS,Filter(function thistype.Filt))
if dat.target == null then
call PauseTimer(t)
call TimerStart(t,INTERVAL,true,function thistype.ReturnHammer)
else
static if not BOUNCE_BACK then
call GroupAddUnit(dat.stack,dat.target)
endif
endif
endif
if dat.bounce >= MAX_BOUNCE or null == dat.target then
call PauseTimer(t)
call TimerStart(t,INTERVAL,true,function thistype.ReturnHammer)
endif
set t = null
endmethod
static method start takes nothing returns boolean
local thistype dat
local real angle
local timer t = NewTimer()
set dat = thistype.allocate()
set dat.caster = GetTriggerUnit()
set dat.target = GetSpellTargetUnit()
set dat.dmg = GetDmg(GetUnitAbilityLevel(dat.caster,ABILITY_ID))
set dat.bounce = 0
static if not BOUNCE_BACK then
set dat.stack = CreateGroup()
call GroupAddUnit(dat.stack,dat.target)
endif
set angle = Atan2(GetUnitY(dat.target) - GetUnitY(dat.caster), GetUnitX(dat.target) - GetUnitX(dat.caster))
set dat.owner = GetOwningPlayer(dat.caster)
set dat.bolt = CreateUnit(dat.owner,UNIT_ID,GetUnitX(dat.caster),GetUnitY(dat.caster),bj_RADTODEG * angle)
call UnitAddAbility(dat.bolt,STUN_ID)
call SetUnitAbilityLevel(dat.bolt,STUN_ID,GetUnitAbilityLevel(dat.caster,ABILITY_ID))
call SetTimerData(t,dat)
call TimerStart(t,INTERVAL,true,function thistype.OnLoop)
set t = null
return false
endmethod
static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILITY_ID,function thistype.start)
endmethod
endstruct
endscope