Name | Type | is_array | initial_value |
Creep_Face_Ang | real | Yes | |
Creep_Loc | location | Yes | |
Integer | integer | No | |
Temp_Point | location | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
All spells were made for the spell forum at thehelper.net
___________________________________________________________
Spell Descriptions/Requirements:
_____________________
Requires NewGen Editor and Key Timers 2 (included in this map).
Jump spell with area damage on impact plus bonus damage after a few seconds, increased bonus damage for enemies that did not move.
Implementation Instructions:
_____________________________
Copy the triggers WaveCrash and KT, then paste them into your map.
//TESH.scrollpos=13
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ KT ~~ Key Timers 2 ~~ By Jesus4Lyf ~~ Version 1.7.2 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Key Timers?
// - Key Timers attaches structs to timers, or more to the point timed
// effects.
// - You can specify different periods.
// - Key Timers only uses one timer with one trigger per low period
// to keep things efficient, especially within the looping.
// - Key Timers alternatively uses one trigger per instance for all higher
// periods to allow accurate expirations in a stable and efficient fashion.
//
// =Pros=
// - Easy to use.
// - Fastest attachment loading system (storing in parallel arrays).
// - Fastest execution system for low periods (all functions on one trigger).
// - Allows multiple periods to be used.
// - No H2I. Backwards compatability through patch 1.23 and 1.24.
//
// =Cons=
// - The code passed into KT2 must call KT_GetData exactly once.
// - Periods must be a multiple of 0.00125 seconds. Not 0.007, for example.
//
// Functions:
// - KT_Add(userFunc, struct, period)
// - KT_GetData returns the struct
//
// - userFunc is to be a user function that takes nothing and returns boolean.
// It will be executed by the system every period until it returns true.
//
// - KT_GetData is to be used inside func, it will return the struct passed to
// to the Add function. It must be called exactly once within the func.
//
// Details:
// - KT2 treats low periods and high periods differently, optimizing each
// with appropriate speed and accuracy, although this effect is invisible
// to you, the mapper.
//
// - While func returns false the timer will continue to call it each period.
// Once func returns true the instance will be detached from system.
//
// Thanks:
// - Daxtreme: For encouraging me to return to Key Timers 2, rather than
// leave it to rot. His interest in the system restored it, and helped
// it to become what it is now. :)
//
// - Captain Griffen: For his work on Rapid Timers, demonstrating that it
// is possible to attach all functions to one trigger, and that it is
// indeed faster.
//
// - Cohadar: Told me to make Key Timers without a textmacro.
// Thanks to him for helping me with the original Key Timers system too.
// Also, I'd like to thank him for his work on Timer Ticker (TT) which
// demonstrated how to use triggers/conditions in this sort of system,
// which has been used in Key Timers 2.
//
// How to import:
// - Create a trigger named KT.
// - Convert it to custom text and replace the whole trigger text with this.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library KT initializer Init
///////////////
// Constants //
////////////////////////////////////////////////////////////////////////////
// That bit that users may play with if they know what they're doing.
// Not touching these at all is recommended.
globals
// Period Threshold is the point at which Key Timers 2 will switch from
// using the single timer per period mechanism to using TAZO, which is
// better for higher periods due to the first tick being accurate.
private constant real PERIODTHRESHOLD=0.3 // MUST be below 10.24 seconds.
// Tazo's number of precached instances. You can go over this during
// your map at runtime, but it will probably do some small background
// processing. Precaching just speeds things up a bit.
private constant integer TAZO_PRECACHE=64
// Tazo uses the low period part of Key Timers 2 to construct triggers
// over time when precached ones run out. Here you can set the period used.
private constant real TAZO_CONSTRUCT_PERIOD=0.03125
endglobals
//////////////////////////
// Previous KT2 Globals //
////////////////////////////////////////////////////////////////////////////
// These needed to be moved here for TAZO to hook GetData.
globals
private timer array KeyTimer
private trigger array TimerTrigger
private integer array KeyTimerListPointer
private integer array KeyTimerListEndPointer
private triggercondition array TriggerCond
private boolexpr array Boolexpr
private integer array Data
private integer array Next
private integer array Prev
private integer TrigMax=0
private integer array NextMem
private integer NextMemMaxPlusOne=1
private integer array ToAddMem
private triggercondition array ToRemove
private boolexpr array ToDestroy
private boolean array IsAdd
private integer AddRemoveMax=0
// Locals
private integer t_id=-1
private integer t_mem
private integer t_lastmem
private integer a_id
private integer a_mem
// Code Chunks
private conditionfunc RemoveInstanceCond
endglobals
//////////////////
// Previous KT2 //
////////////////////////////////////////////////////////////////////////////
// The KT2 implementation
private function KeyTimerLoop takes nothing returns nothing
set t_id=R2I(TimerGetTimeout(GetExpiredTimer())*800)
set t_mem=KeyTimerListEndPointer[t_id]
call TriggerEvaluate(TimerTrigger[t_id])
set t_mem=0
loop
exitwhen t_mem==AddRemoveMax
set t_mem=t_mem+1
if IsAdd[t_mem] then
set TriggerCond[ToAddMem[t_mem]]=TriggerAddCondition(TimerTrigger[t_id],Boolexpr[ToAddMem[t_mem]])
else
call TriggerRemoveCondition(TimerTrigger[t_id],ToRemove[t_mem])
call DestroyBoolExpr(ToDestroy[t_mem])
endif
endloop
set AddRemoveMax=0
set t_id=-1
endfunction
private function RemoveInstance takes nothing returns boolean
// Will only fire if code returns true.
set AddRemoveMax=AddRemoveMax+1
set IsAdd[AddRemoveMax]=false
set ToRemove[AddRemoveMax]=TriggerCond[t_lastmem]
set ToDestroy[AddRemoveMax]=Boolexpr[t_lastmem]
if Next[t_lastmem]==0 then
set KeyTimerListEndPointer[t_id]=Prev[t_lastmem]
endif
set Prev[Next[t_lastmem]]=Prev[t_lastmem]
if Prev[t_lastmem]==0 then
set KeyTimerListPointer[t_id]=Next[t_lastmem]
if KeyTimerListPointer[t_id]<1 then
call PauseTimer(KeyTimer[t_id])
endif
else
set Next[Prev[t_lastmem]]=Next[t_lastmem]
endif
set NextMem[NextMemMaxPlusOne]=t_lastmem
set NextMemMaxPlusOne=NextMemMaxPlusOne+1
return false
endfunction
private function KTadd takes code func, integer data, real period returns nothing
set a_id=R2I(period*800)
if KeyTimer[a_id]==null then
set KeyTimer[a_id]=CreateTimer()
set TimerTrigger[a_id]=CreateTrigger()
endif
if NextMemMaxPlusOne==1 then
set TrigMax=TrigMax+1
set a_mem=TrigMax
else
set NextMemMaxPlusOne=NextMemMaxPlusOne-1
set a_mem=NextMem[NextMemMaxPlusOne]
endif
set Boolexpr[a_mem]=And(Condition(func),RemoveInstanceCond)
if t_id==a_id then
set AddRemoveMax=AddRemoveMax+1
set IsAdd[AddRemoveMax]=true
set ToAddMem[AddRemoveMax]=a_mem
else
if KeyTimerListPointer[a_id]<1 then
call TimerStart(KeyTimer[a_id],a_id/800.0,true,function KeyTimerLoop)
set KeyTimerListEndPointer[a_id]=a_mem
endif
set TriggerCond[a_mem]=TriggerAddCondition(TimerTrigger[a_id],Boolexpr[a_mem])
endif
set Data[a_mem]=data
set Prev[a_mem]=0
set Next[a_mem]=KeyTimerListPointer[a_id]
set Prev[KeyTimerListPointer[a_id]]=a_mem
set KeyTimerListPointer[a_id]=a_mem
endfunction
public function GetData takes nothing returns integer // Gets hooked by TAZO.
set t_lastmem=t_mem
set t_mem=Prev[t_mem]
return Data[t_lastmem]
endfunction
private function KTinit takes nothing returns nothing
set RemoveInstanceCond=Condition(function RemoveInstance)
endfunction
//////////
// TAZO //
////////////////////////////////////////////////////////////////////////////
// KT2 implementation for higher periods (low frequency).
globals
private constant integer TAZO_DATAMEM=8190 // Added for KT2 hook. Don't change.
endglobals
globals
private conditionfunc TAZO_LoadDataCond
private conditionfunc TAZO_RemoveInstanceCond
private timer array TAZO_TrigTimer
private integer array TAZO_Data
private boolexpr array TAZO_Boolexpr
private trigger array TAZO_AvailableTrig
private integer TAZO_Max=0
private integer TAZO_ConstructNext=0
private trigger array TAZO_ConstructTrig
private integer array TAZO_ConstructCount
endglobals
globals//locals
private integer TAZO_ConKey
endglobals
private function TAZO_Constructer takes nothing returns boolean
set TAZO_ConKey=GetData()
call TriggerExecute(TAZO_ConstructTrig[TAZO_ConKey])
set TAZO_ConstructCount[TAZO_ConKey]=TAZO_ConstructCount[TAZO_ConKey]-1
if TAZO_ConstructCount[TAZO_ConKey]==0 then
set TAZO_Max=TAZO_Max+1
set TAZO_AvailableTrig[TAZO_Max]=TAZO_ConstructTrig[TAZO_ConKey]
set TAZO_TrigTimer[TAZO_ConKey]=CreateTimer()
call TriggerRegisterTimerExpireEvent(TAZO_AvailableTrig[TAZO_Max],TAZO_TrigTimer[TAZO_ConKey])
return true
endif
return false
endfunction
globals//locals
private trigger TAZO_DeadTrig
private integer TAZO_DeadCount
endglobals
private function TAZO_Recycle takes nothing returns boolean
set TAZO_DeadTrig=GetTriggeringTrigger()
set TAZO_DeadCount=GetTriggerExecCount(TAZO_DeadTrig)
call TriggerClearConditions(TAZO_DeadTrig)
call DestroyBoolExpr(TAZO_Boolexpr[TAZO_DeadCount])
call PauseTimer(TAZO_TrigTimer[TAZO_DeadCount])
set TAZO_Max=TAZO_Max+1
set TAZO_AvailableTrig[TAZO_Max]=TAZO_DeadTrig
return false
endfunction
private function TAZO_LoadData takes nothing returns boolean
// KT2 Data Hook
set t_mem=TAZO_DATAMEM
set Data[TAZO_DATAMEM]=TAZO_Data[GetTriggerExecCount(GetTriggeringTrigger())]
// End KT2 Data Hook
return false
endfunction
private function InitTrigExecCount takes trigger t, integer d returns nothing
if d>128 then
call InitTrigExecCount.execute(t,d-128)
set d=128
endif
loop
exitwhen d==0
set d=d-1
call TriggerExecute(t)
endloop
endfunction
globals//locals
private integer TAZO_AddKey
private trigger TAZO_AddTrigger
endglobals
public function TAZOadd takes code func, integer data, real period returns nothing
if TAZO_Max==0 then
// Failsafe.
set TAZO_ConstructNext=TAZO_ConstructNext+1
set TAZO_AddTrigger=CreateTrigger()
set TAZO_AddKey=TAZO_ConstructNext
call InitTrigExecCount.execute(TAZO_AddTrigger,TAZO_AddKey)
set TAZO_TrigTimer[TAZO_AddKey]=CreateTimer()
call TriggerRegisterTimerExpireEvent(TAZO_AddTrigger,TAZO_TrigTimer[TAZO_AddKey])
else
set TAZO_AddTrigger=TAZO_AvailableTrig[TAZO_Max]
set TAZO_AddKey=GetTriggerExecCount(TAZO_AddTrigger)
set TAZO_Max=TAZO_Max-1
endif
set TAZO_Data[TAZO_AddKey]=data
set TAZO_Boolexpr[TAZO_AddKey]=And(Condition(func),TAZO_RemoveInstanceCond)
call TriggerAddCondition(TAZO_AddTrigger,TAZO_LoadDataCond)
call TriggerAddCondition(TAZO_AddTrigger,TAZO_Boolexpr[TAZO_AddKey])
call TimerStart(TAZO_TrigTimer[TAZO_AddKey],period,true,null)
if TAZO_Max<10 then
set TAZO_ConstructNext=TAZO_ConstructNext+1
set TAZO_ConstructTrig[TAZO_ConstructNext]=CreateTrigger()
set TAZO_ConstructCount[TAZO_ConstructNext]=TAZO_ConstructNext
call KTadd(function TAZO_Constructer,TAZO_ConstructNext,TAZO_CONSTRUCT_PERIOD)
endif
endfunction
private function TAZOinit takes nothing returns nothing
set TAZO_LoadDataCond=Condition(function TAZO_LoadData)
set TAZO_RemoveInstanceCond=Condition(function TAZO_Recycle)
// Allow for GetData
set Next[TAZO_DATAMEM]=TAZO_DATAMEM
set Prev[TAZO_DATAMEM]=TAZO_DATAMEM
// End allow for GetData
loop
exitwhen TAZO_Max==TAZO_PRECACHE
set TAZO_ConstructNext=TAZO_ConstructNext+1 // The index.
set TAZO_Max=TAZO_Max+1 // Will be the same in the initialiser as ConstructNext.
set TAZO_AvailableTrig[TAZO_Max]=CreateTrigger()
call InitTrigExecCount.execute(TAZO_AvailableTrig[TAZO_Max],TAZO_ConstructNext)
set TAZO_TrigTimer[TAZO_ConstructNext]=CreateTimer()
call TriggerRegisterTimerExpireEvent(TAZO_AvailableTrig[TAZO_Max],TAZO_TrigTimer[TAZO_ConstructNext])
endloop
endfunction
///////////////
// Interface //
////////////////////////////////////////////////////////////////////////////
// Stitches it all together neatly.
public function Add takes code func, integer data, real period returns nothing
if period<PERIODTHRESHOLD then
call KTadd(func,data,period)
else
call TAZOadd(func,data,period)
endif
endfunction
private function Init takes nothing returns nothing
call KTinit()
call TAZOinit()
endfunction
endlibrary
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// End of Key Timers 2
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//TESH.scrollpos=0
//TESH.alwaysfold=0
//***************************************************************************
// Spell: Wave Crash version 1.1 *
// Description: Turn into a special effect and deal area damage on landing. *
// Deals additional damage to impact units after an interval. *
// Requires: vJASS (NewGen Editor), Key Timers 2 *
// MUI/Leakless *
// *
// Change Log: *
// *
// 1.1 *
// Removed a useless variable. *
// *
// 1.0c *
// Fixed a bug that makes the unit stuck if user gets a very rare *
// 0 distance target location. *
// *
// 1.0b *
// Tooltip Grammatical Error :P *
//***************************************************************************
library WaveCrash initializer Init requires KT
globals
private constant integer WCSPELLID = 'Awcc' // Wave Crash spell ID. Press ctrl + D to see it in the ability editor.
private constant integer WCCROWFORM = 'Amrf' // Crow Form spell ID.
private constant boolean WCINVULNERABLE = false // Invulnerable while crashing?
private constant real WCDAMAGEBONUS = 50. // How much bonus damage it does regardless of level.
private constant real WCDAMAGELEVEL = 30. // How much damage it gains per level.
private constant real WCSTRMULT = 0. // Converts fraction of strength (per level) into damage.
private constant real WCAGIMULT = 0.3 // Converts fraction of agility (per level) into damage. 0.3 means 30%.
private constant real WCINTMULT = 0. // Converts fraction of intelligence (per level) into damage.
private constant real WCAFTERDAMAGE = 0.4 // What fraction of the crash damage is dealt a while later, 0.4 means 40%.
private constant real WCAFTERINTERVAL = 2.0 // How many seconds before the after-damage is dealt. Multiple of 0.1.
private constant real WCAFTERBONUS = 0.2 // Fraction of the crash damage dealt in addition to after-damage if target still in range.
private constant attacktype WCATTACKTYPE = ATTACK_TYPE_NORMAL // Attack type, NORMAL = spell, others are HERO, PIERCE, SIEGE, CHAOS, etc.
private constant damagetype WCDAMAGETYPE = DAMAGE_TYPE_MAGIC // Damage type, MAGIC, NORMAL (physical), UNIVERSAL (pure).
private constant weapontype WCWEAPONTYPE = WEAPON_TYPE_WHOKNOWS // Weapon type, determines the sound of impact.
private constant boolean WCDAMAGESTRUCTURES = true // Does it hurt structures?
private constant boolean WCDAMAGEALLIES = false // Does it hurt allies?
private constant real WCSTRUCTMULT = 1.0 // Fraction of damage vs. buildings.
private constant real WCHEIGHT = 1200. // Max height.
private constant real WCAIRTIME = 1. // How long the caster stays in the air.
private constant real WCRADIUS = 400. // Radius of effect. Note, this has to be slightly higher than the area of effect in the ability editor.
private constant real WCINTERVAL = 0.03 // Interval of sliding.
private constant string WCTRAILSFX = "Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl" // Trailing special effect.
private constant string WCTRAILSFXATTACH = "origin" // Trail attach point.
private constant string WCIMPACTSFX = "Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl" // Impact special effect.
private constant string WCIMPACTSFXATTACH = "origin" // Impact attach point.
//*********************** No Touching Below This Line unless you know JASS. ***********************
private constant real WCRISE = 2 * WCHEIGHT / WCAIRTIME
private constant real WCGRAV = 2 * WCRISE / WCAIRTIME
private group G = CreateGroup()
private player P
endglobals
private struct aftercrash
unit source
unit victim
real duration
real damage
real x
real y
method onDestroy takes nothing returns nothing
set this.source = null
set this.victim = null
set this.duration = 0.
set this.damage = 0.
set this.x = 0
set this.y = 0
endmethod
endstruct
private struct wavecrash
unit caster
integer M
real damage
real rise
real speed
real angle
real distance
real z
method onDestroy takes nothing returns nothing
call UnitRemoveAbility(this.caster, WCCROWFORM)
call PauseUnit(this.caster, false)
call SetUnitPathing(this.caster, true)
call SetUnitVertexColor(this.caster, 255, 255, 255, 255)
call SetUnitFlyHeight(this.caster, GetUnitDefaultFlyHeight(this.caster), 0)
if (WCINVULNERABLE) then
call SetUnitInvulnerable(this.caster, false)
endif
set this.caster = null
set this.M = 0
set this.damage = 0
set this.rise = 0
set this.speed = 0
set this.angle = 0
set this.z = 0
endmethod
endstruct
//******************************************************************************
private function WC_AfterCrash takes nothing returns boolean
local aftercrash ac = KT_GetData()
local effect Effect
if (GetUnitState(ac.victim, UNIT_STATE_LIFE) <= 0.) then
call ac.destroy()
return true
endif
if (ac.duration <= 0.) then
if (IsUnitInRangeXY(ac.victim, ac.x, ac.y, WCRADIUS)) then
call UnitDamageTarget(ac.source, ac.victim, ac.damage * (1. + WCAFTERBONUS / WCAFTERDAMAGE), false, false, WCATTACKTYPE, WCDAMAGETYPE, WCWEAPONTYPE)
else
call UnitDamageTarget(ac.source, ac.victim, ac.damage, false, false, WCATTACKTYPE, WCDAMAGETYPE, WCWEAPONTYPE)
endif
set Effect = AddSpecialEffectTarget(WCIMPACTSFX, ac.victim, WCIMPACTSFXATTACH)
call DestroyEffect(Effect)
call ac.destroy()
return true
endif
set ac.duration = ac.duration - 0.1
return false
endfunction
//******************************************************************************
private function WC_TargetCheck takes nothing returns boolean
if (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) <= 0.) then
return false
endif
if (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)) and (not WCDAMAGESTRUCTURES) then
return false
endif
if (IsUnitAlly(GetFilterUnit(), P)) and (not WCDAMAGEALLIES) then
return false
endif
return true
endfunction
//******************************************************************************
private function WC_KillTrees takes nothing returns nothing
if (GetDestructableLife(GetEnumDestructable()) <= 50) then
call KillDestructable(GetEnumDestructable())
endif
endfunction
//******************************************************************************
private function WC_Jump takes nothing returns boolean
local wavecrash wc = KT_GetData()
local aftercrash ac
local real x
local real y
local real z
local real x2
local real y2
local rect r
local unit u
local integer i
local location L
local effect Effect
if (GetUnitState(wc.caster, UNIT_STATE_LIFE) <= 0) then
call wc.destroy()
return true
endif
if (GetUnitFlyHeight(wc.caster) < 1) and (wc.M >= 0.5 * WCAIRTIME / WCINTERVAL) then
set x = GetUnitX(wc.caster)
set y = GetUnitY(wc.caster)
set i = 1
loop
exitwhen i > 8
set x2 = x + (WCRADIUS / 2.) * Cos(45. * I2R(i) * bj_DEGTORAD)
set y2 = y + (WCRADIUS / 2.) * Sin(45. * I2R(i) * bj_DEGTORAD)
set Effect = AddSpecialEffect(WCIMPACTSFX, x2, y2)
call DestroyEffect(Effect)
set i = i + 1
endloop
set r = Rect(x - WCRADIUS, y - WCRADIUS, x + WCRADIUS, y + WCRADIUS)
call EnumDestructablesInRect(r, null, function WC_KillTrees)
set P = GetOwningPlayer(wc.caster)
call GroupEnumUnitsInRect(G, r, Condition(function WC_TargetCheck))
call GroupRemoveUnit(G, wc.caster)
set u = FirstOfGroup(G)
loop
exitwhen IsUnitGroupEmptyBJ(G)
set ac = aftercrash.create()
set ac.source = wc.caster
set ac.victim = u
set ac.damage = WCAFTERDAMAGE * wc.damage
set ac.duration = WCAFTERINTERVAL
set ac.x = x
set ac.y = y
if (IsUnitType(u, UNIT_TYPE_STRUCTURE)) then
call UnitDamageTarget(wc.caster, u, wc.damage * WCSTRUCTMULT, false, false, WCATTACKTYPE, WCDAMAGETYPE, WCWEAPONTYPE)
set ac.damage = ac.damage * WCSTRUCTMULT
else
call UnitDamageTarget(wc.caster, u, wc.damage, false, false, WCATTACKTYPE, WCDAMAGETYPE, WCWEAPONTYPE)
endif
call KT_Add(function WC_AfterCrash, ac, 0.1)
call GroupRemoveUnit(G, u)
set u = FirstOfGroup(G)
endloop
set u = null
set P = null
call GroupClear(G)
call RemoveRect(r)
call wc.destroy()
return true
endif
set x = GetUnitX(wc.caster)
set y = GetUnitY(wc.caster)
set x2 = x + WCINTERVAL * wc.speed * Cos(wc.angle * bj_DEGTORAD)
set y2 = y + WCINTERVAL * wc.speed * Sin(wc.angle * bj_DEGTORAD)
if (IsTerrainPathable(x2, y2, PATHING_TYPE_FLYABILITY)) then
set x2 = x
set y2 = y
endif
set L = Location(x2, y2)
set z = GetLocationZ(L)
call SetUnitPosition(wc.caster, x2, y2)
call SetUnitFlyHeight(wc.caster, (GetUnitFlyHeight(wc.caster) + (wc.rise * WCINTERVAL) + (wc.z - z)), 0)
if (ModuloInteger(wc.M, 5) == 0) then
set Effect = AddSpecialEffectTarget(WCTRAILSFX, wc.caster, WCTRAILSFXATTACH)
call DestroyEffect(Effect)
endif
set wc.z = GetLocationZ(L)
call RemoveLocation(L)
set wc.M = wc.M + 1
set wc.rise = wc.rise - (WCGRAV * WCINTERVAL)
return false
endfunction
//******************************************************************************
private function Wave_Crash takes nothing returns nothing
local location castloc
local location targetloc
local real x
local real y
local real x2
local real y2
local real distance
local real time
local wavecrash wc
if (GetSpellAbilityId() == WCSPELLID) then
set targetloc = GetSpellTargetLoc()
set x = GetUnitX(GetTriggerUnit())
set y = GetUnitY(GetTriggerUnit())
set castloc = Location(x, y)
set x2 = GetLocationX(targetloc)
set y2 = GetLocationY(targetloc)
set distance = SquareRoot((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y))
set wc = wavecrash.create()
set wc.caster = GetTriggerUnit()
set wc.damage = WCDAMAGEBONUS + I2R(GetUnitAbilityLevel(wc.caster, WCSPELLID)) * (WCDAMAGELEVEL + WCSTRMULT * I2R(GetHeroStr(wc.caster, true)) + WCAGIMULT * I2R(GetHeroAgi(wc.caster, true)) + WCINTMULT * I2R(GetHeroInt(wc.caster, true)))
set wc.rise = WCRISE
set wc.speed = distance / WCAIRTIME
set wc.angle = bj_RADTODEG * Atan2(y2 - y, x2 - x)
set wc.distance = distance
set wc.z = GetLocationZ(castloc)
set wc.M = 0
call RemoveLocation(castloc)
call RemoveLocation(targetloc)
if (WCINVULNERABLE) then
call SetUnitInvulnerable(wc.caster, true)
endif
call SetUnitVertexColor(wc.caster, 0, 0, 0, 0)
call PauseUnit(wc.caster, true)
call SetUnitPathing(wc.caster, false)
call UnitAddAbility(wc.caster, WCCROWFORM)
call KT_Add(function WC_Jump, wc, WCINTERVAL)
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 Wave_Crash)
endfunction
endlibrary