Moderator
M
Moderator
08:17, 14th Apr 2010
TriggerHappy:
Coding seemed fine and the spell was nice.
TriggerHappy:
Coding seemed fine and the spell was nice.
scope DarkAgility initializer init
//*************************************************************************************************************//
// Dark Agility v0.01 //
// by //
// cedi //
// //
// needs: TimerUtils by Vexorian //
// Bound Sentinel by Vexorian //
// Dummy Model by //
// IsTerrainWalkable by Antiarf //
// IsUnitNearLine by peq //
//*************************************************************************************************************//
//For use, copy the trigger to your map, copy the dummy create a spell and adjust the values below.
private keyword Main
private keyword Shadow
private keyword Arrow
globals
//ID of the spell
private constant integer SPELL_ID = 'A000'
private constant integer DUMMY_ID = 'h000'
private constant integer HERO_DUMMY_ID = 'h001'
//Interval of the moves
private constant real TIMER_INTERVAL = 0.01
//Main
private constant integer COLOR_RED = 125
private constant integer COLOR_GREEN = 125
private constant integer COLOR_BLUE = 125
private constant integer COLOR_ALPHA = 255
private constant integer ANIMATION = 6
private constant real SPEED = 1000.00
private constant real ILLU_TIME = 0.5
private constant real SHADOW_INTERVAL = 0.035
private constant real PICK_INTERVAL = 0.20
private constant real ANI_TIME = 1.334
private constant real ANI_SPEED = 15.00
private constant real ANI_SPEED_SHADOW = 1.00
private constant real SHADOW_SIZE = 1.00
private constant real Z_START = 60.00
private constant string DAMAGE_SFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
//Arrow
private constant integer A_COLOR_RED = 255
private constant integer A_COLOR_GREEN = 255
private constant integer A_COLOR_BLUE = 255
private constant integer A_COLOR_ALPHA = 125
private constant real SHOOT_RANGE = 600.00
private constant real SHOOT_SPEED = 600.00
private constant real SHOOT_AOE = 10.00
private constant real SHOOT_SIZE = 1.00
private constant string SHOOT_MODEL = "Abilities\\Weapons\\Arrow\\ArrowMissile.mdl"
private constant string SHOOT_ADD = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
private constant string SHOOT_DMG_SFX = "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl"
//System
private Main TEMPMAIN
private Arrow TEMPARROW
private Shadow TEMPSHADOW
private group TEMPGROUP = CreateGroup()
endglobals
private function HIT_FUNC takes Main m, unit target returns nothing
//Do your uber crazy things, like knockback, dot, slow ...
endfunction
private function ARROW_HIT_FUNC takes Arrow a returns nothing
//Do your uber crazy things, like knockback, dot, slow ... //Care arrow gets destroyed after call
endfunction
private function DAMAGE takes integer level returns real
return 100.00 + 50 * level
endfunction
private function ARROW_DAMAGE takes integer level returns real
return 100.00 + 50 * level
endfunction
private function AOE takes integer level returns real
return 55.00 + 5 * level
endfunction
private function CD takes integer level returns real
return 0.10 - 0.01 * level
endfunction
//*************************************************************************************************************//
// !SYSTEM! //
//*************************************************************************************************************//
private function AngleBetweenUnits takes unit u, unit u2 returns real
return bj_RADTODEG * Atan2(GetUnitY( u2 ) - GetUnitY( u ), GetUnitX( u2 ) - GetUnitX( u ))
endfunction
private function AngleBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
private function DistanceBetweenCoordinates takes real x1, real x2, real y1, real y2 returns real
local real dx = x2 - x1
local real dy = y2 - y1
return SquareRoot(dx * dx + dy * dy)
endfunction
private function IsAliveAndUnitAndNotMagicImmune takes nothing returns boolean
return GetWidgetLife( GetFilterUnit() ) > 0.405 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false
endfunction
private function A_OuterControl takes nothing returns nothing
set TEMPARROW = GetTimerData( GetExpiredTimer() )
call TEMPARROW.control()
endfunction
private function OuterControl takes nothing returns nothing
set TEMPMAIN = GetTimerData( GetExpiredTimer() )
call TEMPMAIN.control()
endfunction
private function RemoveShadow takes nothing returns nothing
local timer t = GetExpiredTimer()
set TEMPSHADOW = GetTimerData( t )
set TEMPSHADOW.alpha = TEMPSHADOW.alpha - TEMPSHADOW.alphaneg
call SetUnitVertexColor( TEMPSHADOW.u, COLOR_RED, COLOR_GREEN, COLOR_BLUE, R2I( TEMPSHADOW.alpha - 0.5 ) )
if TEMPSHADOW.alpha <= 0.00 then
call KillUnit( TEMPSHADOW.u )
call RemoveUnit( TEMPSHADOW.u )
call ReleaseTimer( t )
endif
set t = null
endfunction
private struct Shadow
unit u = null
real alpha = 0.00
real alphaneg = 0.00
static method create takes unit u returns thistype
local thistype this = thistype.allocate()
set .u = u
set .alpha = COLOR_ALPHA
set .alphaneg = .alpha * TIMER_INTERVAL / ILLU_TIME
return this
endmethod
endstruct
private struct Arrow
unit u = null
unit caster = null
unit target = null
integer level = 1
effect model = null
effect add = null
timer t = null
method onDestroy takes nothing returns nothing
call DestroyEffect( AddSpecialEffectTarget( SHOOT_DMG_SFX, .target, "chest" ) )
call UnitDamageTarget( .caster, .target, ARROW_DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
call ARROW_HIT_FUNC( this )
call DestroyEffect( .model )
call DestroyEffect( .add )
set .model = null
set .add = null
call KillUnit( .u )
set .u = null
set .caster = null
set .target = null
call ReleaseTimer( .t )
set .t = null
endmethod
method control takes nothing returns nothing
local real angle = AngleBetweenUnits( .u, .target )
local real x = GetUnitX( .u )
local real y = GetUnitY( .u )
local real z = GetUnitFlyHeight( .target ) - GetUnitFlyHeight( .u )
local integer times = 0
call SetUnitFacing( .u, angle )
set angle = angle * bj_DEGTORAD
set x = x + Cos( angle ) * SHOOT_SPEED * TIMER_INTERVAL
set y = y + Sin( angle ) * SHOOT_SPEED * TIMER_INTERVAL
set times = R2I( DistanceBetweenCoordinates( GetUnitX( .u ), x, GetUnitY( .u ), y ) / ( SHOOT_SPEED * TIMER_INTERVAL ) + 0.5 )
call SetUnitX( .u, x )
call SetUnitY( .u, y )
if IsUnitInRange( .u, .target, SHOOT_AOE ) then
call .destroy()
return
endif
if z != 0.00 then
call SetUnitFlyHeight( .u, GetUnitFlyHeight( .u ) + z / times, 0 )
endif
endmethod
static method create takes unit caster, unit target, integer level returns thistype
local thistype this = thistype.allocate()
set .caster = caster
set .target = target
set .u = CreateUnit( GetOwningPlayer( caster ), DUMMY_ID, GetUnitX( caster ), GetUnitY( caster ), 0.00 )
set .level = level
set .model = AddSpecialEffectTarget( SHOOT_MODEL, .u, "origin" )
set .add = AddSpecialEffectTarget( SHOOT_ADD, .u, "origin" )
set .t = NewTimer()
call SetUnitFlyHeight( .u, Z_START, 0 )
call SetTimerData( .t, this )
call TimerStart( .t, TIMER_INTERVAL, true, function A_OuterControl )
call SetUnitScale( .u, SHOOT_SIZE, SHOOT_SIZE, SHOOT_SIZE )
call SetUnitVertexColor( .u, A_COLOR_RED, A_COLOR_GREEN, A_COLOR_BLUE, A_COLOR_ALPHA )
return this
endmethod
endstruct
private struct Main
unit caster = null
real targx = 0.00
real targy = 0.00
real x = 0.00
real y = 0.00
real vx = 0.00
real vy = 0.00
real angle = 0.00
real distance = 0.00 //Distance moved
real fdistance = 0.00 //Full distance
real pickint = 0.00
real shadowint = 0.00
real aniint = 0.00
real shotint = 0.00
integer level = 1
integer i = 0
timer t = null
group g = null
group targets = null
method shot takes nothing returns nothing
local unit u = GroupPickRandomUnit( .targets )
if u != null then
call Arrow.create( .caster, u, .level )
endif
set u = null
endmethod
method createShadow takes nothing returns nothing
local timer t = NewTimer()
local unit u = CreateUnit( Player( 12 ), HERO_DUMMY_ID, .x, .y, .angle )
set TEMPSHADOW = Shadow.create( u )
call SetUnitTimeScale( u, ANI_SPEED_SHADOW )
call SetUnitAnimationByIndex( u, ANIMATION )
call SetUnitScale( u, SHADOW_SIZE, SHADOW_SIZE, SHADOW_SIZE )
call SetUnitVertexColor( u, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_ALPHA )
call SetTimerData( t, TEMPSHADOW )
call TimerStart( t, TIMER_INTERVAL, true, function RemoveShadow )
endmethod
method pick takes nothing returns nothing
local unit u = null
call GroupEnumUnitsInRange( TEMPGROUP, .x, .y, AOE( .level ), Condition( function IsAliveAndUnitAndNotMagicImmune ) )
loop
set u = FirstOfGroup( TEMPGROUP )
if IsUnitEnemy( u, GetOwningPlayer( .caster ) ) then
if not IsUnitInGroup( u, .g ) then
call DestroyEffect( AddSpecialEffectTarget( DAMAGE_SFX, u, "chest" ) )
call UnitDamageTarget( .caster, u, DAMAGE( .level ), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null )
call HIT_FUNC( this, u )
call GroupAddUnit( .g, u )
endif
endif
call GroupRemoveUnit( TEMPGROUP, u )
set u = null
endloop
endmethod
method control takes nothing returns nothing
if .i == 3 then
call PauseUnit( .caster, true )
else
set .i = .i + 1
endif
if .distance >= .fdistance then
call .destroy()
endif
set .distance = .distance + SPEED * TIMER_INTERVAL
set .x = .x + .vx
set .y = .y + .vy
call SetUnitX( .caster, .x )
call SetUnitY( .caster, .y )
set .shotint = .shotint + TIMER_INTERVAL
if .shotint >= CD( .level ) then
set .shotint = 0.00
call .shot()
endif
set .pickint = .pickint + TIMER_INTERVAL
if .pickint >= PICK_INTERVAL then
set .pickint = 0.00
call .pick()
endif
set .shadowint = .shadowint + TIMER_INTERVAL
if .shadowint >= SHADOW_INTERVAL then
set .shadowint = 0.00
call .createShadow()
endif
set .aniint = .aniint + TIMER_INTERVAL
if .aniint >= ANI_TIME / ANI_SPEED then
set .aniint = 0.00
call SetUnitAnimationByIndex( .caster, ANIMATION )
endif
endmethod
method onDestroy takes nothing returns nothing
call SetUnitAnimation( .caster, "stand" )
call SetUnitTimeScale( .caster, 1.00 )
call PauseUnit( .caster, false )
call SetUnitInvulnerable( .caster, false )
call SetUnitPathing( .caster, true )
set .caster = null
call GroupClear( .g )
call DestroyGroup( .g )
set .g = null
call GroupClear( .targets )
call DestroyGroup( .targets )
set .targets = null
call ReleaseTimer( .t )
set .t = null
endmethod
static method create takes unit caster, real targx, real targy returns thistype
local thistype this = thistype.allocate()
local integer i
local real x
local real y
local unit u
set .caster = caster
set .targx = targx
set .targy = targy
set .x = GetUnitX( caster )
set .y = GetUnitY( caster )
set .level = GetUnitAbilityLevel( caster, SPELL_ID )
set .t = NewTimer()
call SetTimerData( .t, this )
set .angle = AngleBetweenCoordinates( .x, targx, .y, targy )
set .distance = DistanceBetweenCoordinates( .x, targx, .y, targy )
set .distance = .distance / ( SPEED * TIMER_INTERVAL )
set .vx = Cos( .angle * bj_DEGTORAD ) * SPEED * TIMER_INTERVAL
set .vy = Sin( .angle * bj_DEGTORAD ) * SPEED * TIMER_INTERVAL
set i = R2I( .distance + 0.5 )
set x = .x
set y = .y
set .g = CreateGroup()
set .targets = CreateGroup()
call GroupAddUnitsNearLine( .targets, .x, .y, .targx, .targy, SHOOT_RANGE )
call SetUnitInvulnerable( .caster, true )
call SetUnitPathing( .caster, false )
loop
exitwhen i < 0
set x = x + .vx
set y = y + .vy
if not IsTerrainWalkable( x, y ) then
set .targx = x
set .targy = y
endif
set i = i - 1
endloop
set .distance = 0.00
set .fdistance = DistanceBetweenCoordinates( .x, .targx, .y, .targy )
call GroupAddGroup( .targets, TEMPGROUP )
loop
set u = FirstOfGroup( TEMPGROUP )
exitwhen u == null
if GetUnitTypeId( u ) != DUMMY_ID and GetUnitTypeId( u ) != HERO_DUMMY_ID and IsUnitEnemy( u, GetOwningPlayer( .caster ) ) and GetWidgetLife( u ) > 0.405 and IsUnitType(u, UNIT_TYPE_STRUCTURE) == false and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) == false then
//good target
else
//not good
call GroupRemoveUnit( .targets, u )
endif
call GroupRemoveUnit( TEMPGROUP, u )
set u = null
endloop
call SetUnitTimeScale( .caster, ANI_SPEED )
call SetUnitAnimationByIndex( .caster, ANIMATION )
call TimerStart( .t, TIMER_INTERVAL, true, function OuterControl )
return this
endmethod
endstruct
private function IsSpell takes nothing returns nothing
if GetSpellAbilityId() == SPELL_ID then
call Main.create( GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY() )
endif
endfunction
private function init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddAction( t, function IsSpell )
set t = null
endfunction
endscope