scope StaticFence initializer InitTrig_StaticFence
globals
// The ability's raw code
private constant integer ABILID = 'A000'
// The dummy's raw code
private constant integer DUMMYID = 'h000'
// The item's raw code
private constant integer ITEMID = 'I000'
// The lightning's width is this * 2
private constant real FENCEWIDTH = 150.
// How far the lighning goes
private constant real DISTMAX = 700.
// Average flying height of the balls
private constant real AVGHEIGHT = 50.
// How fast the lightning moves
private constant real SPEED = 15.
// Base damage
private constant real DMG = 50.
// Bonus damage per ability level
private constant real DMGBONUS = 25.
// How fast the lightning widens at the beginning
private constant real WIDTHSPEED = 5.
// Width of the collision rectangle / 2
private constant real WIDTH = 16.
// AoE of Explosion
private constant real AOE = 150.
// Base damage of explosion
private constant real DMGAOE = 50.
// Bonus damage per ability level of the explosion
private constant real DMGBONUSAOE = 25.
// Minimum speed of knockback, less than this -> unit stops
private constant real KBNMINSPEED = 3.
// Initial speed of knockback
private constant real KBSPEED = 30.
// How quickly the knockback speed slows down
private constant real KBDECELERATION = 1.1
// How quickly the balls change flying height
private constant real FHCHANGE = 0.05
// Extra width of the collision rectangle due to the balls
private constant real RECTOFFSET = 32
// Initial visibility of the ball and lightning
private constant integer VISIBILITY = 0
// Period of timers
private constant real TIMEOUT = 0.03
// The lightning's type
private constant string LIGHTNINGTYPE = "DRAM"
private constant attacktype ATKTYPE = ATTACK_TYPE_NORMAL
private constant damagetype DMGTYPE = DAMAGE_TYPE_LIGHTNING
// Effect when the fence hits a unit
private constant string HITEFFECT = "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdl"
// Effect on units when hit by the final explosion
private constant string AOEEFFECT = "Abilities\\Spells\\Orc\\Purge\\PurgeBuffTarget.mdl"
// Effect on units when knocked back
private constant string KBEFFECT = "Abilities\\Spells\\Other\\Tornado\\Tornado_Target.mdl"
/*~~~~~~~~~~~ Dont edit these ~~~~~~~~~~~~*/
private integer kbs = 0
private integer balls = 0
private item PATH_ITEM
private player plr
private unit un
private group grp = CreateGroup()
private real re1
private real re2
private real re3
private real re4
private real re5
private real re6
private real re7
private real re8
private hashtable hash = InitHashtable()
private group ballGroup = CreateGroup()
private timer ballTimer = CreateTimer()
private group kbGroup = CreateGroup()
private timer kbTimer = CreateTimer()
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
endglobals
// Returns a boolean that tells whether the point is inside a rectangle.
// (px , py) = Point to check
// (cx , cy) = lower left corner of the rect
// (ax , ay) = upper left corner
// (bx , by) = lower right corner
function IsPointInRect takes real px , real py , real cx , real cy , real ax , real ay , real bx , real by returns boolean
local real dot1 = (px-cx)*(ax-cx) + (py-cy)*(ay-cy)
local real dot2 = (ax-cx)*(ax-cx) + (ay-cy)*(ay-cy)
local real dot3 = (px-cx)*(bx-cx) + (py-cy)*(by-cy)
local real dot4 = (bx-cx)*(bx-cx) + (by-cy)*(by-cy)
return dot1 >= 0 and dot1 <= dot2 and dot3 >= 0 and dot3 <= dot4
endfunction
private function SF_kb takes nothing returns nothing
local unit u = GetEnumUnit()
local integer id = GetHandleId(u)
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real x2
local real y2
local real speed = LoadReal( hash , id , StringHash("speed") )
local real angle = LoadReal( hash , id , StringHash("angle") )
set speed = speed / KBDECELERATION
set x = x + speed * Cos(angle)
set y = y + speed * Sin(angle)
call SetItemVisible( PATH_ITEM , true )
call SetItemPosition( PATH_ITEM , x , y )
set x2 = GetItemX(PATH_ITEM)
set y2 = GetItemY(PATH_ITEM)
call SetItemVisible( PATH_ITEM , false )
if x == x2 and y == y2 and speed > 2. then
call SetUnitX( u , x )
call SetUnitY( u , y )
call SaveReal ( hash , id , StringHash("speed") , speed )
else
call DestroyEffect(LoadEffectHandle( hash , id , StringHash("e") ) )
call GroupRemoveUnit( kbGroup , u )
call FlushChildHashtable( hash , id )
set kbs = kbs - 1
if kbs == 0 then
call PauseTimer(kbTimer)
endif
endif
set u = null
endfunction
private function kbTimerExpire takes nothing returns nothing
call ForGroup( kbGroup , function SF_kb )
endfunction
private function UnitFilterExplode takes nothing returns boolean
local unit u = GetFilterUnit()
if GetWidgetLife(u) > 0.405 and /*
*/ IsUnitEnemy( u , plr ) /*
*/ then
call UnitDamageTarget( un , u , re1 , false , true , ATKTYPE , DMGTYPE , WEAPON_TYPE_WHOKNOWS )
if IsUnitType( u , UNIT_TYPE_STRUCTURE ) then
call DestroyEffect( AddSpecialEffectTarget( AOEEFFECT , u , "sprite first" ) )
else
call DestroyEffect( AddSpecialEffectTarget( AOEEFFECT , u , "chest" ) )
endif
endif
set u = null
return false
endfunction
private function UnitFilter takes nothing returns boolean
local unit u = GetFilterUnit()
local integer id
if GetWidgetLife(u) > 0.405 and /*
*/ not(IsUnitInGroup( u , bj_lastCreatedGroup )) and /*
*/ IsUnitEnemy( u , plr ) and /*
*/ IsUnitType( u , UNIT_TYPE_GROUND ) and /*
*/ IsPointInRect( GetUnitX(u) , GetUnitY(u) , re1 , re2 , re3 , re4 , re5 , re6 ) /*
*/ then
call GroupAddUnit( bj_lastCreatedGroup , u )
call UnitDamageTarget( un , u , re7 , false , true , ATKTYPE , DMGTYPE , WEAPON_TYPE_WHOKNOWS )
if IsUnitType( u , UNIT_TYPE_STRUCTURE ) then
call DestroyEffect( AddSpecialEffectTarget( HITEFFECT , u , "sprite first" ) )
else
set id = GetHandleId(u)
call GroupAddUnit( kbGroup , u )
call DestroyEffect( AddSpecialEffectTarget( HITEFFECT , u , "chest" ) )
call SaveEffectHandle( hash , id , StringHash("e") , AddSpecialEffectTarget( KBEFFECT , u , "origin" ) )
call SaveReal( hash , id , StringHash("speed") , KBSPEED )
call SaveReal( hash , id , StringHash("angle") , re8 )
set kbs = kbs + 1
if kbs == 1 then
call TimerStart( kbTimer , TIMEOUT , true , function kbTimerExpire )
endif
endif
else
endif
set u = null
return false
endfunction
private function ballLoop takes nothing returns nothing
local unit u = GetEnumUnit()
local integer ID = GetHandleId(u)
local unit caster = LoadUnitHandle( hash , ID , StringHash("caster") )
local unit other = LoadUnitHandle( hash , ID , StringHash("other") )
local integer phase = LoadInteger( hash , ID , StringHash("phase") )
local lightning l = LoadLightningHandle( hash , ID , StringHash("l") )
local real real1
local real real2
local real real3
local real real4
local real real5
local integer i
local location loc1
local location loc2
if phase != 2 and GetWidgetLife(caster) > 0.405 then
if phase == 0 then
set real1 = LoadReal( hash , ID , StringHash("angleSide") )
set real2 = real1 - bj_PI
set real3 = LoadReal( hash , ID , StringHash("sideOffset") ) + WIDTHSPEED
set real4 = LoadReal( hash , ID , StringHash("x") )
set real5 = LoadReal( hash , ID , StringHash("y") )
if real3 >= FENCEWIDTH then
set real3 = FENCEWIDTH
call SetUnitX( u , real4 + real3 * Cos(real1) )
call SetUnitY( u , real5 + real3 * Sin(real1) )
call SetUnitX( other , real4 + real3 * Cos(real2) )
call SetUnitY( other , real5 + real3 * Sin(real2) )
call SetUnitVertexColor( u , 255 , 255 , 255 , 255 )
call SetUnitVertexColor( other , 255 , 255 , 255 , 255 )
call SetLightningColor( l , 1. , 1. , 1. , 1. )
call SaveInteger( hash , ID , StringHash("phase") , 1 )
else
call SetUnitX( u , real4 + real3 * Cos(real1) )
call SetUnitY( u , real5 + real3 * Sin(real1) )
call SetUnitX( other , real4 + real3 * Cos(real2) )
call SetUnitY( other , real5 + real3 * Sin(real2) )
set i = LoadInteger( hash , ID , StringHash("alpha") ) + LoadInteger( hash , ID , StringHash("visiSpeed") )
call SetUnitVertexColor( u , 255 , 255 , 255 , i )
call SetUnitVertexColor( other , 255 , 255 , 255 , i )
call SetLightningColor( l , 1. , 1. , 1. , I2R(i) / 255 )
call SaveInteger( hash , ID , StringHash("alpha") , i )
call SaveReal( hash , ID , StringHash("sideOffset") , real3 )
endif
set loc1 = GetUnitLoc(u)
set loc2 = GetUnitLoc(other)
call MoveLightningEx( l , true , GetUnitX(u) , GetUnitY(u) , GetLocationZ(loc1) + GetUnitFlyHeight(u) , GetUnitX(other) , GetUnitY(other) , GetLocationZ(loc2) + GetUnitFlyHeight(other) )
call RemoveLocation(loc1)
call RemoveLocation(loc2)
else
// Changes the the flying height of the balls
set real1 = LoadReal( hash , ID , StringHash("phase1") )
set real2 = LoadReal( hash , ID , StringHash("phase2") )
call SetUnitFlyHeight( u , AVGHEIGHT + AVGHEIGHT / 2 * Sin(real1) , 0. )
call SetUnitFlyHeight( other , AVGHEIGHT + AVGHEIGHT / 2 * Sin(real2) , 0. )
call SaveReal( hash , ID , StringHash("phase1") , real1 + FHCHANGE )
call SaveReal( hash , ID , StringHash("phase2") , real2 + FHCHANGE )
set re8 = LoadReal( hash , ID , StringHash("angle") )
set real2 = GetUnitX(u) + SPEED * Cos(re8)
set real3 = GetUnitY(u) + SPEED * Sin(re8)
set real1 = re8 - bj_PI / 2
set real4 = real2 + 2 * FENCEWIDTH * Cos(real1)
set real5 = real3 + 2 * FENCEWIDTH * Sin(real1)
call SetUnitX( u , real2 )
call SetUnitY( u , real3 )
call SetUnitX( other , real4 )
call SetUnitY( other , real5 )
set loc1 = Location( real2 , real3 )
set loc2 = Location( real4 , real5 )
call MoveLightningEx( l , true , real2 , real3 , GetLocationZ(loc1) + GetUnitFlyHeight(u) , real4 , real5 , GetLocationZ(loc2) + GetUnitFlyHeight(other) )
call RemoveLocation(loc1)
call RemoveLocation(loc2)
// Lower left corner
set real1 = re8 + 3*bj_PI/4
set real5 = SquareRoot(RECTOFFSET*RECTOFFSET*2)
set re1 = real2 + real5 * Cos(real1)
set re2 = real3 + real5 * Sin(real1)
// Upper left corner
set real1 = re8 + bj_PI/4
set re3 = real2 + real5 * Cos(real1)
set re4 = real3 + real5 * Sin(real1)
// Lower right corner
set real1 = re8 - bj_PI/2
set re5 = re1 + 2 * ( FENCEWIDTH + RECTOFFSET ) * Cos(real1)
set re6 = re2 + 2 * ( FENCEWIDTH + RECTOFFSET ) * Sin(real1)
set bj_lastCreatedGroup = LoadGroupHandle( hash , ID , StringHash("group") )
set plr = GetOwningPlayer(caster)
set un = caster
set re7 = LoadReal( hash , ID , StringHash("damage") )
call GroupEnumUnitsInRange( grp , re1 , re2 , 2.5 * FENCEWIDTH , function UnitFilter )
call GroupClear(grp)
set real1 = LoadReal( hash , ID , StringHash("distance") )
if real1 < DISTMAX then
call SaveReal( hash , ID , StringHash("distance") , real1 + SPEED )
else
call DestroyGroup(bj_lastCreatedGroup)
call SaveInteger( hash , ID , StringHash("phase") , 2 )
endif
endif
else
if GetWidgetLife(caster) > 0.405 then
set un = caster
set plr = GetOwningPlayer(caster)
set re1 = LoadReal( hash , ID , StringHash("damageAOE") )
call GroupEnumUnitsInRange( grp , GetUnitX(u) , GetUnitY(u) , AOE , function UnitFilterExplode )
call GroupClear(grp)
call GroupEnumUnitsInRange( grp , GetUnitX(other) , GetUnitY(other) , AOE , function UnitFilterExplode )
call GroupClear(grp)
endif
call UnitApplyTimedLife( u , 1 , 0.01 )
call UnitApplyTimedLife( other , 1 , 0.01 )
call DestroyLightning(l)
call GroupRemoveUnit( ballGroup , u )
call FlushChildHashtable( hash , ID )
set balls = balls - 1
if balls == 0 then
call PauseTimer(ballTimer)
endif
endif
set l = null
set loc1 = null
set loc2 = null
set u = null
set other = null
set caster = null
endfunction
private function ballTimerExpire takes nothing returns nothing
call ForGroup( ballGroup , function ballLoop )
endfunction
private function SF_Actions takes nothing returns nothing
local unit u = GetTriggerUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real facing = GetUnitFacing(u)
local location loc = GetUnitLoc(u)
local integer level = GetUnitAbilityLevel( u , ABILID ) - 1
local integer ID
local real rnd = GetRandomReal( 0 , 2 * bj_PI )
set bj_lastCreatedUnit = CreateUnit( Player(15) , DUMMYID , x , y , facing )
set ID = GetHandleId(bj_lastCreatedUnit)
call GroupAddUnit( ballGroup , bj_lastCreatedUnit )
call SetUnitExploded( bj_lastCreatedUnit , true )
call SetUnitFlyHeight( bj_lastCreatedUnit , AVGHEIGHT , 0. )
call SetUnitFlyHeight( bj_lastCreatedUnit , AVGHEIGHT + AVGHEIGHT / 2 * Sin(rnd) , 0. )
call SetUnitVertexColor( bj_lastCreatedUnit , 255 , 255 , 255 , VISIBILITY )
call SaveReal( hash , ID , StringHash("phase1") , rnd )
set rnd = GetRandomReal( 0 , 2 * bj_PI )
set bj_lastCreatedUnit = CreateUnit( Player(15) , DUMMYID , x , y , facing )
call SetUnitExploded( bj_lastCreatedUnit , true )
call SetUnitFlyHeight( bj_lastCreatedUnit , AVGHEIGHT , 0. )
call SetUnitFlyHeight( bj_lastCreatedUnit , AVGHEIGHT + AVGHEIGHT / 2 * Sin(rnd) , 0. )
call SetUnitVertexColor( bj_lastCreatedUnit , 255 , 255 , 255 , VISIBILITY )
call SaveReal( hash , ID , StringHash("phase2") , rnd )
set bj_lastCreatedLightning = AddLightningEx( LIGHTNINGTYPE , true , x , y , GetLocationZ(loc) + AVGHEIGHT , x + 1 , y + 1 , GetLocationZ(loc) + AVGHEIGHT )
call SetLightningColor( bj_lastCreatedLightning , 1 , 1 , 1 , VISIBILITY )
call SaveReal( hash , ID , StringHash("x") , x )
call SaveReal( hash , ID , StringHash("y") , y )
call SaveReal( hash , ID , StringHash("angle") , facing * bj_DEGTORAD )
call SaveReal( hash , ID , StringHash("sideOffset") , 0. )
call SaveReal( hash , ID , StringHash("angleSide") , (facing + 90) * bj_DEGTORAD )
call SaveReal( hash , ID , StringHash("damage") , DMG + DMGBONUS * level )
call SaveReal( hash , ID , StringHash("damageAOE") , DMGAOE + DMGBONUSAOE * level )
call SaveUnitHandle( hash , ID , StringHash("caster") , u )
call SaveUnitHandle( hash , ID , StringHash("other") , bj_lastCreatedUnit )
call SaveInteger( hash , ID , StringHash("alpha") , VISIBILITY )
call SaveInteger( hash , ID , StringHash("visiSpeed") , R2I(I2R(255-VISIBILITY) / ( FENCEWIDTH / WIDTHSPEED )) )
call SaveLightningHandle( hash , ID , StringHash("l") , bj_lastCreatedLightning )
call SaveGroupHandle( hash , ID , StringHash("group") , CreateGroup() )
set balls = balls + 1
if balls == 1 then
call TimerStart( ballTimer , TIMEOUT , true , function ballTimerExpire )
endif
call RemoveLocation(loc)
set u = null
endfunction
private function SF_Conditions takes nothing returns boolean
return GetSpellAbilityId() == ABILID
endfunction
private function InitTrig_StaticFence takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t , EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( t , Condition( function SF_Conditions ) )
call TriggerAddAction( t , function SF_Actions )
set PATH_ITEM = CreateItem( ITEMID , 0 , 0 )
call SetItemVisible( PATH_ITEM , false )
endfunction
endscope