Obscurity, the Art
Projects Director Project Leader: OD
Join Date: Feb 2006
Posts: 9,725
Deadeye Spell Pack
Deadeye Spell Pack (Hero Contest #3)
Background:
This is a spell pack I made for an entry in the
3rd WC3C Hero Contest . The skills were designed for use in the melee environment and some of them have some object editor dependencies. Other than those requirements, the spells can easily be ported to any map individually or as a group for use in your maps. The skills were also designed with the
Deadeye Model , by
Jigrael , in mind. BoundSentinel technically isn't required for any of the abilities to work, but it is used with the skills at my recommendation.
Requirements: Spells Included:
Spells:
Barrage
Actively Cast
Shoots arrows at units in the target area, dealing damage.
Level 1 - Small area, 75 damage.
Level 2 - Medium area, 130 damage.
Level 3 - Large area, 200 damage.Rickets
Actively Cast
Decrepifies the target unit's skeletal structure, causing it to have reduced armor and movement speed.
Lasts 16 seconds.
Level 1 - 4 less armor, 20% slow.
Level 2 - 6 less armor, 40% slow.
Level 3 - 8 less armor, 60% slow.Graverobber
Passive
As long as the Deadeye is within range of corpses, he is invisible.
Level 1 - 3 corpses.
Level 2 - 2 corpses.
Level 3 - 1 corpse.Quench Life
Actively Cast, Channeled
Creates a swirling vortex of life draining energies, stealing 20 life per second from all foes in range and evenly distributing it to allies in range.
Code:
Barrage:
scope Barrage initializer Init
globals
private constant integer SPELL_ID = 'A000'
private constant integer DUMMY_ID = 'h000'
private constant real TIMER_INTERVAL = 0.04
private constant real AOE_BUFFER = 30.
private constant real RANGE_THRESHOLD_SQUARED = 2025.
private constant real DUMMY_MOVE_SPEED = 900.
private constant real DUMMY_UNIT_HEIGHT = 65.
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_UNIVERSAL
private constant real X_OFFSET = -15.
private constant real Y_OFFSET = 40.
private constant string EFFECT_POINT = "origin"
private timer MoveTimer = CreateTimer ()
private boolean ToStart = false
private boolexpr Checker = null
private player TempPlayer = null
private integer Counter = 0
private integer array Arrows
private trigger Trg = CreateTrigger ()
private constant integer SPELL_TARGET = 1
private constant integer SPELL_POINT = 2
endglobals
private constant function Damage takes integer lvl returns real
return 7.5 *lvl *lvl + 32.5 *lvl + 35.
endfunction
private constant function AreaOfEffect takes integer lvl returns real
return 160. +40. *lvl
endfunction
private constant function Targets takes integer lvl returns integer
return lvl +2
endfunction
private function Check takes nothing returns boolean
return IsUnitEnemy (GetFilterUnit (), TempPlayer ) and IsUnitType (GetFilterUnit (), UNIT_TYPE_GROUND ) and not IsUnitType (GetFilterUnit (), UNIT_TYPE_STRUCTURE ) and GetWidgetLife (GetFilterUnit ()) > 0.405 and not IsUnitSpellResistant (GetFilterUnit ()) and GetUnitAbilityLevel (GetFilterUnit (), 'Avul' ) <= 0.
endfunction
private struct arrow
integer Flag = 0
integer Level = 0
unit Source = null
unit Target = null
unit Dummy = null
effect Fx = null
real Angle = 0.
real x = 0.
real y = 0.
static method create takes unit u , unit t , real xi , real yi , real xf , real yf , integer flag , integer lvl , real angle returns arrow
local arrow a = arrow.allocate ()
set a.Source = u
set a.Target = t
set a.Dummy = CreateUnit (GetOwningPlayer (u ), DUMMY_ID , xi , yi , angle *bj_RADTODEG )
set a.Level = lvl
set a.Flag = flag
set a.Angle = angle
set a.Fx = AddSpellEffectTargetById (SPELL_ID , EFFECT_TYPE_MISSILE , a.Dummy , "origin" )
call SetUnitX (a.Dummy , xi )
call SetUnitY (a.Dummy , yi )
if IsUnitType (a.Dummy , UNIT_TYPE_GROUND ) then
call UnitAddAbility (a.Dummy , 'Amrf' )
call UnitRemoveAbility (a.Dummy , 'Amrf' )
endif
call SetUnitFlyHeight (a.Dummy , DUMMY_UNIT_HEIGHT , 0. )
if flag == SPELL_POINT then
set a.x = xf
set a.y = yf
else
set a.x = GetUnitX (t )
set a.y = GetUnitY (t )
endif
return a
endmethod
private method onDestroy takes nothing returns nothing
call DestroyEffect (this.Fx )
if this.Flag == 1 then
call DestroyEffect (AddSpellEffectTargetById (SPELL_ID , EFFECT_TYPE_TARGET , this.Target , EFFECT_POINT ))
else
call DestroyEffect (AddSpellEffectById (SPELL_ID , EFFECT_TYPE_TARGET , this.x , this.y ))
endif
call KillUnit (this.Dummy )
endmethod
endstruct
private function Conditions takes nothing returns boolean
return GetSpellAbilityId () == SPELL_ID
endfunction
private function Callback takes nothing returns nothing
local unit u = null
local unit d = null
local unit t = null
local arrow a = 0
local integer i = Counter - 1
local integer j = 0
local integer lvl = 0
local real xi = 0.
local real yi = 0.
local real xf = 0.
local real yf = 0.
local real di = 0.
local real an = 0.
loop
exitwhen i < 0
set a = Arrows [i ]
set u = a.Source
set t = a.Target
set d = a.Dummy
set lvl = a.Level
set xi = GetUnitX (d )
set yi = GetUnitY (d )
if a.Flag == SPELL_TARGET then
set a.x = GetUnitX (t )
set a.y = GetUnitY (t )
set a.Angle = Atan2 (a.y -yi , a.x -xi )
call SetUnitFacing (d , a.Angle *bj_RADTODEG )
endif
set di = (a.x -xi )*(a.x -xi )+(a.y -yi )*(a.y -yi )
if di <= RANGE_THRESHOLD_SQUARED then
if a.Flag == SPELL_TARGET then
call UnitDamageTarget (u , t , Damage (lvl ), false , false , ATTACK_TYPE , DAMAGE_TYPE , null )
endif
call a.destroy ()
set Counter = Counter - 1
if Counter < 0 then
call PauseTimer (MoveTimer )
set Counter = 0
else
set Arrows [i ] = Arrows [Counter ]
endif
else
set di = DUMMY_MOVE_SPEED *TIMER_INTERVAL
set xf = xi + di *Cos (a.Angle )
set yf = yi + di *Sin (a.Angle )
call SetUnitX (d , xf )
call SetUnitY (d , yf )
endif
set i = i - 1
endloop
set u = null
set d = null
set t = null
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit ()
local unit s = null
local location l = GetSpellTargetLoc ()
local integer lvl = GetUnitAbilityLevel (u , SPELL_ID )
local integer c = 0
local integer o = Counter
local integer m = Targets (lvl )
local arrow a = 0
local real xi = GetUnitX (u )
local real yi = GetUnitY (u )
local real xf = GetLocationX (l )
local real yf = GetLocationY (l )
local real di = 0.
local real ag = Atan2 (yf -yi , xf -xi )
local real x = 0.
local real y = 0.
local real an = 0.
if X_OFFSET != 0. then
set an = ag -bj_PI /2
set xi = xi + X_OFFSET *Cos (an )
set yi = yi + X_OFFSET *Sin (an )
endif
if Y_OFFSET != 0. then
set an = ag
set xi = xi + Y_OFFSET *Cos (an )
set yi = yi + Y_OFFSET *Sin (an )
endif
set TempPlayer = GetOwningPlayer (u )
call GroupEnumUnitsInRange (ENUM_GROUP , xf , yf , AreaOfEffect (lvl ), Checker )
loop
set bj_groupRandomConsidered = 0
set bj_groupRandomCurrentPick = null
call ForGroup (ENUM_GROUP , function GroupPickRandomUnitEnum )
set s = bj_groupRandomCurrentPick
exitwhen s == null or c >= m
set an = Atan2 (GetUnitY (s )-yi , GetUnitX (s )-xi )
set a = arrow.create (u , s , xi , yi , 0. , 0. , SPELL_TARGET , lvl , an )
set Arrows [Counter ] = integer (a )
set Counter = Counter + 1
call GroupRemoveUnit (ENUM_GROUP , s )
set c = c + 1
endloop
if c < m then
loop
exitwhen c >= m
set di = GetRandomReal (AOE_BUFFER *2 , AreaOfEffect (lvl )-AOE_BUFFER )
set ag = GetRandomReal (0 , 2 *bj_PI )
set x = xf + di *Cos (ag )
set y = yf + di *Sin (ag )
set an = Atan2 (y -yi , x -xi )
set a = arrow.create (u , null , xi , yi , x , y , SPELL_POINT , lvl , an )
set Arrows [Counter ] = integer (a )
set Counter = Counter + 1
set c = c + 1
endloop
endif
if o == 0 then
call TimerStart (MoveTimer , TIMER_INTERVAL , true , function Callback )
endif
call GroupClear (ENUM_GROUP )
call RemoveLocation (l )
set l = null
set u = null
set s = null
endfunction
private function Init takes nothing returns nothing
call TriggerAddAction (Trg , function Actions )
call TriggerAddCondition (Trg , Condition (function Conditions ))
call TriggerRegisterAnyUnitEventBJ (Trg , EVENT_PLAYER_UNIT_SPELL_EFFECT )
set Checker = Condition (function Check )
endfunction
endscope
Rickets:
scope Rickets initializer Init
globals
private constant integer SPELL_ID = 'A003'
private constant integer ARMOR_ID = 'A002'
private constant integer BUFFABIL_ID = 'A004'
private constant integer BUFF_ID = 'B000'
private constant real SCAN_INTERVAL = 0.1
private group TargGroup = CreateGroup ()
private timer ScanTimer = CreateTimer ()
private real array Duration
private integer array Level
private trigger Trg = CreateTrigger ()
endglobals
private constant function UnitSpellDuration takes integer lvl returns real
return 16.
endfunction
private constant function HeroSpellDuration takes integer lvl returns real
return 8.
endfunction
private function EndConditions takes unit u , integer lvl returns boolean
return GetWidgetLife (u ) < 0.405
endfunction
private function Conditions takes nothing returns boolean
return GetSpellAbilityId () == SPELL_ID
endfunction
private function Enumeration takes nothing returns nothing
local unit e = GetEnumUnit ()
local integer id = GetUnitId (e )
set Duration [id ] = Duration [id ] - SCAN_INTERVAL
if EndConditions (e , Level [id ]) or Duration [id ] <= 0. then
call UnitRemoveAbility (e , ARMOR_ID )
call UnitRemoveAbility (e , BUFFABIL_ID )
call UnitRemoveAbility (e , BUFF_ID )
call GroupRemoveUnit (TargGroup , e )
endif
set e = null
endfunction
private function Callback takes nothing returns nothing
call ForGroup (TargGroup , function Enumeration )
if FirstOfGroup (TargGroup ) == null then
call PauseTimer (ScanTimer )
endif
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit ()
local unit t = GetSpellTargetUnit ()
local integer lvl = GetUnitAbilityLevel (u , SPELL_ID )
local integer id = GetUnitId (t )
if GetUnitAbilityLevel (t , BUFF_ID ) <= 0 then
call UnitAddAbility (t , ARMOR_ID )
call UnitAddAbility (t , BUFFABIL_ID )
call SetUnitAbilityLevel (t , ARMOR_ID , lvl )
call SetUnitAbilityLevel (t , BUFFABIL_ID , lvl )
if FirstOfGroup (TargGroup ) == null then
call TimerStart (ScanTimer , SCAN_INTERVAL , true , function Callback )
endif
call GroupAddUnit (TargGroup , t )
endif
if IsUnitType (t , UNIT_TYPE_HERO ) then
set Duration [id ] = HeroSpellDuration (lvl )
else
set Duration [id ] = UnitSpellDuration (lvl )
endif
set Level [id ] = lvl
set u = null
set t = null
endfunction
private function Init takes nothing returns nothing
call TriggerAddAction (Trg , function Actions )
call TriggerAddCondition (Trg , Condition (function Conditions ))
call TriggerRegisterAnyUnitEventBJ (Trg , EVENT_PLAYER_UNIT_SPELL_EFFECT )
endfunction
endscope
Graverobber:
scope Graverobber initializer Init
globals
private constant integer SPELL_ID = 'A001'
private constant integer INVIS_ID = 'Apiv'
private constant real TIMER_INTERVAL = 0.05
private timer CheckTimer = CreateTimer ()
private group CasterGroup = CreateGroup ()
private boolexpr Checker = null
private trigger Trg = CreateTrigger ()
endglobals
private constant function AreaOfEffect takes integer lvl returns real
return 450.
endfunction
private constant function Corpses takes integer lvl returns integer
return 4 -lvl
endfunction
private function Check takes nothing returns boolean
return GetUnitTypeId (GetFilterUnit ()) != 0 and IsUnitType (GetFilterUnit (), UNIT_TYPE_GROUND ) and not IsUnitType (GetFilterUnit (), UNIT_TYPE_SUMMONED ) and not IsUnitType (GetFilterUnit (), UNIT_TYPE_STRUCTURE ) and GetWidgetLife (GetFilterUnit ()) <= 0.405
endfunction
private function Conditions takes nothing returns boolean
return GetLearnedSkill () == SPELL_ID
endfunction
private function Enumeration takes nothing returns nothing
local unit e = GetEnumUnit ()
local unit s = null
local integer lvl = GetUnitAbilityLevel (e , SPELL_ID )
local real x = GetUnitX (e )
local real y = GetUnitY (e )
if GetWidgetLife (e ) > 0.405 then
set bj_groupCountUnits = 0
call GroupEnumUnitsInRange (ENUM_GROUP , x , y , AreaOfEffect (lvl ), Checker )
call ForGroup (ENUM_GROUP , function CountUnitsInGroupEnum )
if bj_groupCountUnits >= Corpses (lvl ) and GetUnitAbilityLevel (e , INVIS_ID ) <= 0 then
call UnitAddAbility (e , INVIS_ID )
elseif bj_groupCountUnits < Corpses (lvl ) and GetUnitAbilityLevel (e , INVIS_ID ) > 0 then
call UnitRemoveAbility (e , INVIS_ID )
endif
endif
call GroupClear (ENUM_GROUP )
set e = null
set s = null
endfunction
private function Callback takes nothing returns nothing
call ForGroup (CasterGroup , function Enumeration )
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit ()
if FirstOfGroup (CasterGroup ) == null then
call TimerStart (CheckTimer , TIMER_INTERVAL , true , function Callback )
endif
call GroupAddUnit (CasterGroup , u )
set u = null
endfunction
private function Init takes nothing returns nothing
call TriggerAddAction (Trg , function Actions )
call TriggerAddCondition (Trg , Condition (function Conditions ))
call TriggerRegisterAnyUnitEventBJ (Trg , EVENT_PLAYER_HERO_SKILL )
set Checker = Condition (function Check )
endfunction
endscope Quench Life:
scope QuenchLife initializer Init
globals
private constant integer SPELL_ID = 'A005'
private constant integer DUMMY_ID = 'h000'
private constant string ORDER_STRING = "starfall"
private constant integer LIGHTNING_COUNT = 6
private constant integer LIGHTNING_TO_GO_LEFT = 3
private constant string LIGHTNING_TYPE = "DRAL"
private constant real LIGHTNING_Z_OFFSET = 450.
private constant real LIGHTNING_ANGLE_OFFSET = 2 *bj_PI /3
private constant real LIGHTNING_ANGLE_SHIFT = bj_PI /40
private constant real AREA_OF_EFFECT = 600.
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_UNIVERSAL
private constant real TIMER_INTERVAL = 0.10
private constant integer ITERATIONS_TIL_EFFECT = 5
private constant string EFFECT_POINT = "origin"
private group CastGroup = CreateGroup ()
private timer ScanTimer = CreateTimer ()
private player TempPlayer = null
private boolexpr HealChecker = null
private boolexpr DamageChecker = null
private integer array Glowies
private trigger Trg = CreateTrigger ()
endglobals
private constant function LifeStolen takes integer lvl returns real
return 20.
endfunction
private function EndConditions takes unit u , integer lvl returns boolean
return GetUnitCurrentOrder (u ) != OrderId (ORDER_STRING )
endfunction
private function DamageCheck takes nothing returns boolean
return IsUnitEnemy (GetFilterUnit (), TempPlayer ) and not IsUnitType (GetFilterUnit (), UNIT_TYPE_STRUCTURE ) and GetWidgetLife (GetFilterUnit ()) > 0.405 and GetUnitAbilityLevel (GetFilterUnit (), 'Avul' ) <= 0.
endfunction
private function HealCheck takes nothing returns boolean
return IsUnitAlly (GetFilterUnit (), TempPlayer ) and not IsUnitType (GetFilterUnit (), UNIT_TYPE_STRUCTURE ) and GetWidgetLife (GetFilterUnit ()) > 0.405 and GetUnitAbilityLevel (GetFilterUnit (), 'Avul' ) <= 0.
endfunction
private struct glowyhax
lightning array orbital [4 ]
integer level = 0
integer index = 0
unit attach = null
real angle1 = 0.
real angle2 = 0.
static method create takes unit u returns glowyhax
local glowyhax g = glowyhax.allocate ()
local integer i = 1
local real x = GetUnitX (u )
local real y = GetUnitY (u )
set g.attach = CreateUnit (GetOwningPlayer (u ), DUMMY_ID , x , y , 0. )
set g.level = GetUnitAbilityLevel (u , SPELL_ID )
set g.angle1 = GetUnitFacing (u )*bj_DEGTORAD
set g.angle2 = g.angle1 + bj_PI /2
if IsUnitType (g.attach , UNIT_TYPE_GROUND ) then
call UnitAddAbility (g.attach , 'Amrf' )
call UnitRemoveAbility (g.attach , 'Amrf' )
endif
call SetUnitFlyHeight (g.attach , LIGHTNING_Z_OFFSET , 0. )
call PauseUnit (g.attach , true )
call SetUnitX (g.attach , x )
call SetUnitY (g.attach , y )
loop
exitwhen i > LIGHTNING_COUNT
set g.orbital [i ] = null
set i = i + 1
endloop
return g
endmethod
private method onDestroy takes nothing returns nothing
local integer i = 1
loop
exitwhen i > LIGHTNING_COUNT
call DestroyLightning (this.orbital [i ])
set i = i + 1
endloop
call KillUnit (this.attach )
endmethod
endstruct
private function Conditions takes nothing returns boolean
return GetSpellAbilityId () == SPELL_ID
endfunction
private function Enumeration takes nothing returns nothing
local unit e = GetEnumUnit ()
local unit s = null
local integer id = GetUnitId (e )
local glowyhax g = Glowies [id ]
local integer lvl = g.level
local integer i = 1
local location l = GetUnitLoc (e )
local real dmg = LifeStolen (lvl )
local real xi = GetLocationX (l )
local real yi = GetLocationY (l )
local real zi = GetLocationZ (l )
local real xf = 0.
local real yf = 0.
local real zf = 0.
local real a = g.angle1
local real r = 0.
call RemoveLocation (l )
loop
exitwhen i > LIGHTNING_COUNT
set xf = xi + AREA_OF_EFFECT *Cos (a )
set yf = yi + AREA_OF_EFFECT *Sin (a )
set l = Location (xf , yf )
set zf = GetLocationZ (l )
call RemoveLocation (l )
if g.orbital [i ] != null then
call MoveLightningEx (g.orbital [i ], true , xi , yi , LIGHTNING_Z_OFFSET +zi , xf , yf , zf )
else
set g.orbital [i ] = AddLightningEx (LIGHTNING_TYPE , true , xi , yi , LIGHTNING_Z_OFFSET +zi , xf , yf , zf )
endif
call DestroyEffect (AddSpellEffectTargetById (SPELL_ID , EFFECT_TYPE_EFFECT , g.attach , "origin" ))
call DestroyEffect (AddSpellEffectById (SPELL_ID , EFFECT_TYPE_EFFECT , xf , yf ))
if i < LIGHTNING_TO_GO_LEFT then
set a = a - LIGHTNING_ANGLE_OFFSET
elseif i == LIGHTNING_TO_GO_LEFT then
set a = g.angle2
elseif i > LIGHTNING_TO_GO_LEFT then
set a = a + LIGHTNING_ANGLE_OFFSET
endif
set i = i + 1
endloop
set g.angle1 = g.angle1 + LIGHTNING_ANGLE_SHIFT
set g.angle2 = g.angle2 - LIGHTNING_ANGLE_SHIFT
set g.index = g.index + 1
set TempPlayer = GetOwningPlayer (e )
call GroupEnumUnitsInRange (ENUM_GROUP , xi , yi , AREA_OF_EFFECT , DamageChecker )
loop
set s = FirstOfGroup (ENUM_GROUP )
exitwhen s == null
if ModuloInteger (g.index , ITERATIONS_TIL_EFFECT ) == 0 then
call DestroyEffect (AddSpellEffectTargetById (SPELL_ID , EFFECT_TYPE_TARGET , s , EFFECT_POINT ))
endif
call UnitDamageTarget (e , s , dmg *TIMER_INTERVAL , false , false , ATTACK_TYPE , DAMAGE_TYPE , null )
set r = r + dmg *TIMER_INTERVAL
call GroupRemoveUnit (ENUM_GROUP , s )
endloop
call GroupEnumUnitsInRange (ENUM_GROUP , xi , yi , AREA_OF_EFFECT , HealChecker )
if FirstOfGroup (ENUM_GROUP ) != null and r > 0. then
set bj_groupCountUnits = 0
call ForGroup (ENUM_GROUP , function CountUnitsInGroupEnum )
set r = r / bj_groupCountUnits
loop
set s = FirstOfGroup (ENUM_GROUP )
exitwhen s == null
if ModuloInteger (g.index , ITERATIONS_TIL_EFFECT ) == 0 then
call DestroyEffect (AddSpellEffectTargetById (SPELL_ID , EFFECT_TYPE_SPECIAL , s , EFFECT_POINT ))
endif
call SetWidgetLife (s , GetWidgetLife (s ) + dmg )
call GroupRemoveUnit (ENUM_GROUP , s )
endloop
endif
if EndConditions (e , lvl ) then
call GroupRemoveUnit (CastGroup , e )
call g.destroy ()
endif
call GroupClear (ENUM_GROUP )
set e = null
set s = null
set l = null
endfunction
private function Callback takes nothing returns nothing
call ForGroup (CastGroup , function Enumeration )
if FirstOfGroup (CastGroup ) == null then
call PauseTimer (ScanTimer )
endif
endfunction
private function Actions takes nothing returns nothing
local unit u = GetTriggerUnit ()
local integer id = GetUnitId (u )
local glowyhax g = glowyhax.create (u )
if FirstOfGroup (CastGroup ) == null then
call TimerStart (ScanTimer , TIMER_INTERVAL , true , function Callback )
endif
call GroupAddUnit (CastGroup , u )
set Glowies [id ] = g
set u = null
endfunction
private function Init takes nothing returns nothing
call TriggerAddAction (Trg , function Actions )
call TriggerAddCondition (Trg , Condition (function Conditions ))
call TriggerRegisterAnyUnitEventBJ (Trg , EVENT_PLAYER_UNIT_SPELL_EFFECT )
set DamageChecker = Condition (function DamageCheck )
set HealChecker = Condition (function HealCheck )
endfunction
endscope
Attached Images
Attached Files
__________________
"DAMAGE_TYPE_POISON motherfucker!" ~Anitarf
Last edited by Rising_Dusk : 08-25-2009 at 09:13 PM .