Алгоритмы, Наработки и Способности
Способ реализации:
Прочее
Тип:
Способность
Версия Warcraft:
1.26
Spirit Breaker прямо из доты 6.83d
СПИСОК ИСПРАВЛЕНИЙ
ChargeOfDarkness :
Теперь можно изучать прямо во время разбега или перезарядки способности
EmpoweringHaste :
Теперь не сбивает текущий приказ и не проигрывает анимацию spell morph
(но сбивает ChargeOfDarkness)
Сделано на основе "Стремительность", вместо "Берсерк"!
NetherStrike :
При получении стана или если цель далеко убежит, то способность автоматически отменяется
Написано на vJass с define из cJass
Почти у каждой функции есть комментарий того, что делает функция
Все используемые абилки и т.д лежат в константах у каждой библиотеки
DotA
library DotA initializer DotaInit    
    
    
    globals
    
        hashtable udg_dotaHash  = InitHashtable()
        timer     udg_dotaTimer = CreateTimer()
        region    global_region //Регион в котором не будет работать отталкивание юнита от GreaterBash
        
    endglobals
    
    
    private function DotaInit takes nothing returns nothing
        set global_region = CreateRegion()
        //В регион надо добавлять области в которых не будет работать отталкивание юнита от GreaterBash
        //Пример:
        //call RegionAddRect( global_region, bj_mapInitialPlayableArea )
        call TimerStart( udg_dotaTimer, 99999.00, false, null )
    endfunction
    
endlibrary
DestroyTrigger
library DestroyTriggerEx initializer InitDestroyTrigger requires DotA


    globals
    
        private trigger array triggers
        private real    array time
        private integer       count = 0
    
    endglobals

    
    private function ErrorMsg takes nothing returns nothing
        //Выводит сообщение об ошибке
        local integer i = 0

        loop
            call DisplayTimedTextToPlayer(Player(i), 0, 0, 120, "|c00ff0303An internal checksum has failed|r" )
            set i = i+1
            exitwhen i == 12
        endloop

    endfunction

    function DestroyTriggerEx takes trigger trg returns nothing
        //Добавляет триггер в очередь для удаления
        call DisableTrigger( trg )
        set count = count+1
        set triggers[count] = trg
        set time[count] = TimerGetElapsed(udg_dotaTimer)+60
        if count > 8000 then
            call ErrorMsg()
        endif
    endfunction

    private function ClearQueue takes integer i returns nothing
        if i != count then
            set triggers[i] = triggers[count]
            set time[i] = time[count]
        endif
    
        set triggers[count] = null
        set time[count] = 0
        set count = count-1
    endfunction

    private function DestroyTrigger_Actions takes nothing returns boolean
        local real r = TimerGetElapsed(udg_dotaTimer)
        local integer i
    
        set i = 1
        loop
            exitwhen i > count
            if time[i] < r then
                if triggers[i] == null or IsTriggerEnabled(triggers[i]) == true then
                    call ErrorMsg()
                else
                    call DestroyTrigger( triggers[i] )
                endif
                call ClearQueue( i )
            else
                set i = i + 1
            endif
        endloop
    
        return false
    endfunction

    private function InitDestroyTrigger takes nothing returns nothing
        local trigger trg = CreateTrigger()
    
        call TriggerRegisterTimerEvent( trg, 15, true )
        call TriggerAddCondition( trg, Condition(function DestroyTrigger_Actions) )
    endfunction

endlibrary
Recycle
library Recycle initializer InitRecycle requires DotA
    
    
    globals
        
        private group   array groups
        private boolean array groupIsUsed
        private boolean       error              = false
        private integer       firstGroupHandleId = 0
        private integer       number             = 0
        private real          errorTime          = 0.
        private string        errorText          = ""
        
    endglobals
    
    
    private function Display takes nothing returns nothing
        call DisplayTimedTextToPlayer( GetEnumPlayer(), 0, 0, errorTime, errorText )
    endfunction

    private function DisplayError takes force f, real r, string s returns nothing
        set errorText = s
        set errorTime = r
        call ForForce( f, function Display )
    endfunction
    
    function RecycleGroup takes group g returns nothing
        //Функция очищает группу и делает её доступной для повторного использования
        local integer i = GetHandleId(g)-firstGroupHandleId
        if i < 0 or i > 120 then
            set error = true
        else
            call GroupClear( g )
            set groupIsUsed[i] = false
            set number = i
        endif
    endfunction

    function GetGroup takes nothing returns group
        //Возвращает доступную для использования группу
        local integer i = number

        loop
            exitwhen i == number-1
            if groupIsUsed[i] == false then
                set number = i+1
                if number == 120 then
                    set number = 0
                endif
                set groupIsUsed[i] = true
                return groups[i]
            endif
            set i = i+1
            if i == 120 then
                set i = 0
            endif
        endloop
        
        call DisplayError( bj_FORCE_ALL_PLAYERS, 5.00, "|c00ff0303CRITICAL ERROR: FOUND NO AVAILABLE GROUPS|r" )
        
        return CreateGroup()
    endfunction

    function RecycleCheck takes nothing returns boolean
        //Проверка на количество групп которые в данный момент используются
        local integer groupCount = 0
        local integer i = 0
        
        loop
            exitwhen i == 120
            if groupIsUsed[i] == true then
                set groupCount = groupCount+1
            endif
            set i = i+1
        endloop
        
        if groupCount > 100 or error then
            call DisplayError( bj_FORCE_ALL_PLAYERS, 5.00, I2S(groupCount) )
        endif
        
        return false
    endfunction

    private function InitRecycle takes nothing returns nothing
        local integer i = 0
        
        set number = 0
        set groups[i] = CreateGroup()
        set groupIsUsed[i] = false
        set i = i+1
        set firstGroupHandleId = GetHandleId( groups[0] )
        
        loop
            exitwhen i == 120
            set groups[i] = CreateGroup()
            set groupIsUsed[i] = false
            set i = i+1
        endloop
    endfunction
    
    
endlibrary
OtherFunctions
library OtherFunctions requires DotA, DestroyTriggerEx, Recycle


    globals
    
        private integer destroyedDestructables = 0 //Нужно для подсчета уничтоженных разрушаемых объектов
        
        define
            Spellcaster   = 'e00E' //Spellcaster
            PreloaderHero = 'H00Y' //Preloader Hero
            Marker        = 'A04R' //Marker
        enddefine
        
    endglobals

    
    function BlockAbility takes unit u returns boolean
        //Здесь нужно указывать все бафы которые могут блокировать одну направленную способность
        //Пример:
        //return GetUnitAbilityLevel(u, 'B0BI') > 0 or GetUnitAbilityLevel(u, 'BNss') > 0
        return false
    endfunction

    private function BashOn takes nothing returns boolean
        //Включает срабатывание GreaterBash при атаке юнита
        local trigger trg  = GetTriggeringTrigger()
        local integer trgH = GetHandleId( trg )
        
        call SaveInteger( udg_dotaHash, GetHandleId( LoadUnitHandle(udg_dotaHash, trgH, 14) ), LoadInteger(udg_dotaHash, trgH, 33 ), 2 )
        call FlushChildHashtable( udg_dotaHash, trgH )
        call DestroyTriggerEx( trg )
        set trg = null
        
        return false
    endfunction

    function BashOff takes unit u, integer i, real r returns nothing
        //Выключает срабатывание GreaterBash при атаке юнита (не влияет на GreaterBash от способностей)
        local trigger trg = CreateTrigger()
        
        call TriggerAddCondition( trg, Condition(function BashOn) )
        call TriggerRegisterTimerEvent( trg, r, false )
        call SaveInteger   ( udg_dotaHash, GetHandleId(u)   , i  , 1 )
        call SaveUnitHandle( udg_dotaHash, GetHandleId(trg) , 14 , u )
        call SaveInteger   ( udg_dotaHash, GetHandleId(trg) , 33 , i )
        
        set trg = null
    endfunction

    function IsDestructable takes destructable d returns boolean
        //Здесь нужно указывать все деревья и разрушаемые объекты, которые могут быть в карте
        return GetDestructableTypeId(d) == 'NTtc' or GetDestructableTypeId(d) == 'NTtw' or GetDestructableTypeId(d) == 'ATtr' or GetDestructableTypeId(d) == 'LTlt'
    endfunction

    function DamageToUnit takes unit attacker, unit target, integer i, real damage returns nothing
        //Нанесение урона
        if i == 0 then
            return
        endif
        if i == 1 then
            call UnitDamageTarget( attacker, target, damage, true, true, ATTACK_TYPE_NORMAL , DAMAGE_TYPE_FIRE   , WEAPON_TYPE_WHOKNOWS )
        elseif i == 2 then
            call UnitDamageTarget( attacker, target, damage, true, true, ATTACK_TYPE_HERO   , DAMAGE_TYPE_NORMAL , WEAPON_TYPE_WHOKNOWS )
        elseif i == 3 then
            call UnitDamageTarget( attacker, target, damage, true, true, ATTACK_TYPE_HERO   , DAMAGE_TYPE_MAGIC  , WEAPON_TYPE_WHOKNOWS )
        elseif i == 4 then
            call UnitDamageTarget( attacker, target, damage, true, true, ATTACK_TYPE_PIERCE , DAMAGE_TYPE_NORMAL , WEAPON_TYPE_WHOKNOWS )
        elseif i == 5 then
            call UnitDamageTarget( attacker, target, damage, true, true, ATTACK_TYPE_NORMAL , DAMAGE_TYPE_NORMAL , WEAPON_TYPE_WHOKNOWS )
        elseif i == 6 then
            call SetUnitState( target, UNIT_STATE_LIFE, RMaxBJ( GetUnitState(target, UNIT_STATE_LIFE)-damage, 1 ) )
            if GetUnitState( target, UNIT_STATE_LIFE ) < 2 then
                call UnitRemoveBuffs( target, true,true )
                //call UnitRemoveAbility( target, 'Aetl' )
                call UnitDamageTarget( CreateUnit(GetOwningPlayer(attacker), Spellcaster, 0, 0, 0), target, 100000000.00, true, false, ATTACK_TYPE_MELEE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS )
            endif
        elseif i == 7 then
            //В этом if нужно указывать способности имея которые юнит получает больше магического урона
            //Оригинал:
            //if GetUnitAbilityLevel(target, 'Aetl') > 0 or GetUnitAbilityLevel(target, 'B01N') > 0 then
            if false then
                call UnitDamageTarget( attacker, target, damage, true, true, ATTACK_TYPE_HERO, DAMAGE_TYPE_MAGIC     , WEAPON_TYPE_WHOKNOWS )
            else
                call UnitDamageTarget( attacker, target, damage, true, true, ATTACK_TYPE_HERO, DAMAGE_TYPE_UNIVERSAL , WEAPON_TYPE_WHOKNOWS )
            endif
        elseif i == 8 then
            call UnitDamageTarget( attacker, target, damage, true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS )
        endif
    endfunction

    function SafeRealX takes real x returns real
        //Чтобы X не выходила за пределы карты, иначе - вернет значение недалеко от границы игровой карты
        local real r = GetRectMinX(bj_mapInitialPlayableArea)+50
        
        if x < r then
            return r
        endif
        set r = GetRectMaxX(bj_mapInitialPlayableArea)-50
        if x > r then
            return r
        endif
        
        return x
    endfunction

    function SafeRealY takes real y returns real
        //Чтобы Y не выходила за пределы карты, иначе - вернет значение недалеко от границы игровой карты
        local real r = GetRectMinY(bj_mapInitialPlayableArea)+50
        
        if y < r then
            return r
        endif
        set r = GetRectMaxY(bj_mapInitialPlayableArea)-50
        if y > r then
            return r
        endif
        
        return y
    endfunction

    function AbilityInit takes integer i returns nothing
        local unit u = CreateUnit( Player(15), PreloaderHero, 0, 0, 270 )
        
        call UnitAddAbility( u, i )
        call UnitRemoveAbility( u, i )
        call RemoveUnit( u )
        
        set u = null
    endfunction

    function DistanceBetweenUnits takes unit u_1, unit u_2 returns real
        //Возвращает расстояние между координатами юнитов
        local real x1 = GetUnitX( u_1 )
        local real y1 = GetUnitY( u_1 )
        local real x2 = GetUnitX( u_2 )
        local real y2 = GetUnitY( u_2 )
        
        if u_1 == null or u_2 == null then
            return I2R(9999999999)
        else
            return SquareRoot( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) )
        endif
        
        return 1.0
    endfunction

    function DistanceBetweenCoordinates takes real x1, real y1, real x2, real y2 returns real
        //Возвращает расстояние между координатами
        return SquareRoot(  ((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2))  )
    endfunction

    function AngleBetweenUnits takes unit u_1, unit u_2 returns real
        //Возвращает угол между юнитами
        return bj_RADTODEG*Atan2( GetUnitY(u_2)-GetUnitY(u_1), GetUnitX(u_2)-GetUnitX(u_1) )
    endfunction

    function AnyUnitEvent takes trigger trg, playerunitevent whichEvent returns nothing
        local integer i = 0
        
        loop
            call TriggerRegisterPlayerUnitEvent( trg, Player(i), whichEvent, null )
            set i = i+1
            exitwhen i == 16
        endloop
    endfunction

    function KillDestructables_Actions takes nothing returns nothing
        if IsDestructable(GetEnumDestructable()) and IsDestructableAliveBJ(GetEnumDestructable()) then
            set destroyedDestructables = destroyedDestructables + 1
            call KillDestructable( GetEnumDestructable() )
        endif
    endfunction

    function KillDestructables takes real x, real y, real radius returns integer
        //Уничтожение деревьев или декораций, которые мешают
        //Например если отменить ChargeOfDarkness возле деревьев
        //Или юнит-цель в момент столкновения будет находиться возле деревьев
        local rect r = Rect( x-radius, y-radius, x+radius, y+radius )
        
        set destroyedDestructables = 0
        call EnumDestructablesInRect( r, null, function KillDestructables_Actions )
        call RemoveRect( r )
        
        set r = null
        //Возвращает количество уничтоженных разрушаемых объектов
        return destroyedDestructables
    endfunction

    function AddAbility takes unit u, integer i returns nothing
        call UnitAddAbility( u, i )
        call UnitMakeAbilityPermanent( u, true, i )
    endfunction

    function IfUnitExist takes unit u returns boolean
        //Проверка, существует юнит или он мертв
        return GetUnitTypeId(u) < 1 or IsUnitType(u, UNIT_TYPE_DEAD) == true
    endfunction

    function IfHaveStopBuff takes unit u returns boolean
        //Здесь нужно указывать все бафы имея которые ChargeOfDarkness сбивается
        //Пример:
        //return (GetUnitAbilityLevel(u, 'B00H') > 0) or (GetUnitAbilityLevel(u, 'BOhx') > 0)
        return false
    endfunction

    function IfHavePauseOrBuff takes unit u returns boolean
        //Проверка, находится ли юнит в паузе или имеет баф который останавливает применение способности
        return IfHaveStopBuff( u ) or IsUnitPaused( u )
    endfunction

    function Ancient_Exception takes unit u returns boolean
        //Юниты с классификацией "Древо" игнорируются поиском цели
        //Но эта функция делает исключение для некоторых юнитов с этой классификацией
        local integer i = GetUnitTypeId(u)
        
        //Пример:
        //return i == 'n004' or i == 'n01G' or i == 'n01C' or i == 'n018'
        return false
    endfunction

    function CheckUnit takes nothing returns boolean
        //Проверка на враждебность двух юнитов и на то чтобы GetFilterUnit() не был зданием или дамми юнитом
        return IsUnitEnemy(global_caster, GetOwningPlayer(GetFilterUnit()) ) and (GetUnitAbilityLevel( GetFilterUnit(), Marker ) == 0 and IsUnitType( GetFilterUnit(), UNIT_TYPE_STRUCTURE ) == false and IfUnitExist(GetFilterUnit()) == false) and (IsUnitType( GetFilterUnit() ,UNIT_TYPE_ANCIENT ) == false or Ancient_Exception(GetFilterUnit()))
    endfunction

endlibrary
SpellcasterRemove
library SpellcasterRemove initializer InitSpellcasterRemove requires OtherFunctions


    define
        
        Spellcaster = 'e00E' //Spellcaster
        
    enddefine


    private function SpellcasterRemove_Actions takes nothing returns nothing
        local unit u = GetEnteringUnit()
        
        //if GetUnitTypeId( GetEnteringUnit()) == 'e00E' or GetUnitTypeId(GetEnteringUnit()) == 'e022' then
        if GetUnitTypeId( u ) == Spellcaster then
            call ShowUnit( u, false )
            call SetUnitPathing( u, false )
            call SetUnitInvulnerable( u, true )
            call UnitApplyTimedLife( u, 'BTLF', 20.00 )
        endif
        
        set u = null
    endfunction
    
    private function InitSpellcasterRemove takes nothing returns nothing
        local trigger trg = CreateTrigger(  )
        
        call TriggerRegisterEnterRectSimple( trg, bj_mapInitialPlayableArea )
        call TriggerAddCondition( trg, Condition(function SpellcasterRemove_Actions) )
        
        set trg = null
    endfunction
    
    
endlibrary
ChargeOfDarkness
library ChargeOfDarkness initializer InitChargeOfDarkness requires OtherFunctions, GreaterBash


    globals
    
        private real find_distance   = 0.00 //Нужно для сравнивания расстояний, чтобы найти ближайшего юнита (если target умрет)
                unit global_caster   = null //Используется в FindFilter и CheckUnit(OtherFunctions)
        private unit foundUnit       = null //Ближайший юнит к умершему target, это нужно чтобы caster находил новую цель при разбеге (если target умрет)
        private unit darkness_caster = null
        private unit darkness_target = null
        private integer darkness_abilityLvl = 0 //Непонятная integer, нигде не используется
        private group   group_NotBash //Эта группа нужна чтобы на юнитов не накладывался GreaterBash, когда caster бежит

        define
            SwapAbilityContainer    = 'A003' //SwapAbilityContainer
            Cooldown                = 'A312' //Charge of Darkness (on cooldown)
            ChargeOfDarknessAbility = 'A1P8' //Charge of Darkness
            EmpoweringHasteAbility  = 'A004' //Empowering Haste
            NetherStrikeAbility     = 'A0G4' //Nether Strike
            NetherStrikeUpgrade     = 'A1D8' //Nether Strike Upgrade
            GreaterBashAbility      = 'A0G5' //Greater Bash
            AttributeBonus          = 'Aamk' //Attribute Bonus
            Marker                  = 'A04R' //Marker
            ChargeOfDarknessAddBuff = 'A24L' //Charge of Darkness Add Buff
            ChargeOfDarknessBuff    = 'B0ED' //Charge of Darkness (buff)
            SpellImmunity           = 'A179' //Spell Immunity
            Spellcaster             = 'e00E' //Spellcaster
            ChargeOfDarknessStun    = 'A0GS' //Charge of Darkness Stun
            GrandMagus              = 'E02X' //Grand Magus (Rubick)
            VisionDummy             = 'o00Q' //Vision Dummy
            Generic_Stun            = 'A0X6' //Generic_Stun
        enddefine
        
    endglobals
    
    
    private function Cooldown_Remove takes nothing returns boolean
        local trigger trg  = GetTriggeringTrigger()
        local integer trgH = GetHandleId   ( trg )
        local unit    u    = LoadUnitHandle( udg_dotaHash, trgH, 2 )
        
        call UnitRemoveAbility( u, Cooldown )
        call UnitRemoveAbility( u, SwapAbilityContainer )
        call FlushChildHashtable( udg_dotaHash, trgH )
        call DestroyTriggerEx( trg )
        
        set trg = null
        set u   = null
        
        return false
    endfunction

    private function Cooldown_Start takes unit u returns nothing
        //Эта функция запускает триггер который через 12 секунд уберет перезарядку у способности
        local trigger trg
        local integer trgH
        
        if IfUnitExist(u) == true then
            call UnitRemoveAbility( u, Cooldown )
            call UnitRemoveAbility( u, SwapAbilityContainer )
        else
            set trg  = CreateTrigger()
            set trgH = GetHandleId( trg )
            call TriggerRegisterDeathEvent( trg, u )
            call TriggerRegisterTimerEvent( trg, 12, false )
            call TriggerAddCondition( trg, Condition(function Cooldown_Remove) )
            call SaveUnitHandle( udg_dotaHash, trgH, 2, u )
        endif
        
        set trg = null
    endfunction

    private function ChargeOfDarkness_Bash takes nothing returns nothing
        //Если на пути кастера находятся юниты, то на них кидается GreaterBash
        //
        //Строки if IsUnitInGroup( GetEnumUnit(), group_NotBash ) == false then
        //call GroupAddUnit( group_NotBash, GetEnumUnit() )
        //Отвечают за то, чтобы GreaterBash повторно не кидался на юнитов
        if IsUnitInGroup( GetEnumUnit(), group_NotBash ) == false then
            call GroupAddUnit( group_NotBash, GetEnumUnit() )
            call GreaterBash( darkness_caster, GetEnumUnit(), false, true )
        endif
    endfunction

    private function OrderCheck takes integer i returns boolean
        //Проверка на приказ, это нужно чтобы ChargeOfDarkness не сбивался если менять вещи в инвентаре
        if i == ChargeOfDarknessAbility or i == EmpoweringHasteAbility or i == NetherStrikeAbility or i == NetherStrikeUpgrade or i == GreaterBashAbility or i == AttributeBonus then
            return true
        endif
        if i == 852002 or i == 852003 or i == 852004 or i == 852005 or i == 852006 or i == 852007 then
            return true
        endif
        if i > 1000000 then
            return true
        endif
        
        return false
    endfunction

    private function FindFilter takes nothing returns boolean
        //Функция поиска ближайшего юнита
        if (IsUnitEnemy( global_caster, GetOwningPlayer(GetFilterUnit()) ) and (GetUnitAbilityLevel( GetFilterUnit(), Marker ) == 0 and IsUnitType( GetFilterUnit(), UNIT_TYPE_STRUCTURE ) == false and IfUnitExist( GetFilterUnit() ) == false) and (IsUnitType( GetFilterUnit(), UNIT_TYPE_ANCIENT ) == false or Ancient_Exception(GetFilterUnit()) ) ) and IsUnitVisible( GetFilterUnit(), GetOwningPlayer(darkness_caster) ) == true then
            if DistanceBetweenUnits( darkness_target, GetFilterUnit() ) < find_distance then
                set find_distance = DistanceBetweenUnits( darkness_target, GetFilterUnit() )
                set foundUnit = GetFilterUnit()
            endif
        endif
        
        return false
    endfunction

    private function Find takes unit caster, unit target returns unit
        //Поиск ближайшей цели, если target умрет
        local group g = GetGroup()
        
        set global_caster   = caster
        set darkness_caster = caster
        set foundUnit       = null
        set find_distance   = 999999
        set darkness_target = target
        call GroupEnumUnitsInRange( g, GetUnitX(target), GetUnitY(target), 4000, Condition(function FindFilter) )
        call RecycleGroup( g )
        
        set g = null
        
        return foundUnit
    endfunction

    private function ChargeOfDarkness_Move takes nothing returns boolean
        //Главная функция, отвечает за движение, ручную остановку способности и прочее
        local trigger trg              = GetTriggeringTrigger()
        local integer trgH             = GetHandleId( trg )
        local unit    caster           = LoadUnitHandle( udg_dotaHash, trgH, 2 )
        local unit    target           = LoadUnitHandle( udg_dotaHash, trgH, 17 )
        local unit    dummy            = LoadUnitHandle( udg_dotaHash, trgH, 19 )
        local integer abilityLvl       = LoadInteger( udg_dotaHash, trgH, 5 )
        local real    moveReal         = (550+50*abilityLvl)*0.02
        local real    casterX          = LoadReal( udg_dotaHash, trgH, 23 )
        local real    casterY          = LoadReal( udg_dotaHash, trgH, 24 )
        local real    PolarProjectionX
        local real    PolarProjectionY
        local real    moveAngle
        local real    distanceBetweenCasterAndTarget
        local string  effectString
        local group   g
        
        if (GetTriggerEventId() == EVENT_WIDGET_DEATH and GetTriggerUnit() == caster) or GetTriggerEventId() == EVENT_UNIT_ISSUED_ORDER or GetTriggerEventId() == EVENT_UNIT_ISSUED_POINT_ORDER or GetTriggerEventId() == EVENT_UNIT_ISSUED_TARGET_ORDER or IfHavePauseOrBuff(caster) or LoadReal(udg_dotaHash, trgH, 442) < TimerGetElapsed(udg_dotaTimer) then
            if (GetTriggerEventId() != EVENT_UNIT_ISSUED_ORDER and GetTriggerEventId() != EVENT_UNIT_ISSUED_POINT_ORDER and GetTriggerEventId() != EVENT_UNIT_ISSUED_TARGET_ORDER) or ((GetTriggerEventId() == EVENT_UNIT_ISSUED_ORDER or GetTriggerEventId() == EVENT_UNIT_ISSUED_POINT_ORDER or GetTriggerEventId() == EVENT_UNIT_ISSUED_TARGET_ORDER) and OrderCheck(GetIssuedOrderId()) == false) then
                //Останавливает способность если юнит умер, получил паузу/сбивающий бафф, или отдал приказ (кроме приказа для смены положения предметов в инвентаре)
                call Cooldown_Start( caster )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 175) )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 176) )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 177) )
                call UnitRemoveAbility( target, ChargeOfDarknessAddBuff )
                call UnitRemoveAbility( target, ChargeOfDarknessBuff )
                call RecycleGroup( LoadGroupHandle(udg_dotaHash, trgH, 187) )
                call FlushChildHashtable( udg_dotaHash, trgH )
                call DestroyTriggerEx( trg )
                call SetUnitTimeScale( caster, 1 )
                call KillUnit( dummy )
                call SetUnitPathing( caster, true )
                call SetUnitVertexColor( caster, 255, 255, 255, 255 )
                call UnitRemoveAbility( caster, SpellImmunity )
                call KillDestructables( GetUnitX(caster), GetUnitY(caster), 200 )
                if GetTriggerEventId() != EVENT_WIDGET_DEATH then
                    call ResetUnitAnimation( caster )
                endif
            endif
        elseif GetTriggerEventId() == EVENT_WIDGET_DEATH and GetTriggerUnit() == target then
            //Находит новую цель если target умирает
            set effectString = ""
            if IsPlayerAlly( GetLocalPlayer(), GetOwningPlayer(caster) ) then
                set effectString = "Abilities\\Spells\\Other\\HowlOfTerror\\HowlTarget.mdl"
            endif
            call UnitRemoveAbility( target, ChargeOfDarknessAddBuff )
            call UnitRemoveAbility( target, ChargeOfDarknessBuff )
            set target = Find( caster, target )
            if target != null then
                call SaveUnitHandle( udg_dotaHash, trgH, 17, target )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 175) )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 176) )
                call SaveEffectHandle( udg_dotaHash, trgH, 175, AddSpecialEffectTarget(effectString, target, "overhead") )
                call SaveEffectHandle( udg_dotaHash, trgH, 176, AddSpecialEffectTarget(effectString, target, "overhead") )
                call SaveReal( udg_dotaHash, trgH, 442, (TimerGetElapsed(udg_dotaTimer)+50)*1.0 )
                call TriggerRegisterDeathEvent( trg, target )
            else
                call Cooldown_Start( caster )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 175) )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 176) )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 177) )
                call UnitRemoveAbility( target, ChargeOfDarknessAddBuff )
                call UnitRemoveAbility( target, ChargeOfDarknessBuff )
                call RecycleGroup( LoadGroupHandle(udg_dotaHash, trgH, 187) )
                call FlushChildHashtable( udg_dotaHash, trgH )
                call DestroyTriggerEx( trg )
                call SetUnitTimeScale( caster, 1 )
                call KillUnit( dummy )
                call SetUnitPathing( caster, true )
                call ResetUnitAnimation( caster )
                call SetUnitVertexColor( caster, 255, 255, 255, 255 )
                call UnitRemoveAbility( caster, SpellImmunity )
                call SetUnitPosition( caster, GetUnitX(caster), GetUnitY(caster) )
                call KillDestructables( GetUnitX(caster), GetUnitY(caster), 500 )
            endif
        else
            //Движение юнита или остановка по достижению цели
            set distanceBetweenCasterAndTarget = DistanceBetweenCoordinates( GetUnitX(caster), GetUnitY(caster), GetUnitX(target), GetUnitY(target) )
            if distanceBetweenCasterAndTarget < 100 then
                //Завершает ChargeOfDarkness
                call Cooldown_Start( caster )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 175) )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 176) )
                call DestroyEffect( LoadEffectHandle(udg_dotaHash, trgH, 177) )
                call UnitRemoveAbility( target, ChargeOfDarknessAddBuff )
                call UnitRemoveAbility( target, ChargeOfDarknessBuff )
                call RecycleGroup( LoadGroupHandle(udg_dotaHash, trgH, 187) )
                call FlushChildHashtable( udg_dotaHash, trgH )
                call DestroyTriggerEx( trg )
                call SetUnitTimeScale( caster, 1 )
                call KillUnit( dummy )
                set dummy = CreateUnit( GetOwningPlayer(target), Spellcaster, GetUnitX(target), GetUnitY(target), 0 )
                call UnitAddAbility( dummy, ChargeOfDarknessStun )
                call SetUnitAbilityLevel( dummy, ChargeOfDarknessStun, abilityLvl )
                call IssueTargetOrder( dummy, "thunderbolt", target )
                call SetUnitPathing( caster, true )
                call SetUnitVertexColor( caster, 255, 255, 255, 255 )
                call UnitRemoveAbility( caster, SpellImmunity )
                call SetUnitPosition( caster, GetUnitX(caster), GetUnitY(caster) )
                call KillDestructables( GetUnitX(caster), GetUnitY(caster), 200 )
                set darkness_abilityLvl = abilityLvl
                call IssueTargetOrder( caster, "attack", target )
            else
                //Перемещение кастера
                if GetTriggerEvalCount( trg ) == 1 then
                    call DisableTrigger( trg )
                    call IssueImmediateOrder( caster, "holdposition" )
                    call EnableTrigger( trg )
                endif
                if ModuloInteger( GetTriggerEvalCount(trg), 65 ) == 0 then
                    if GetUnitTypeId( caster ) == GrandMagus then
                        call SetUnitAnimationByIndex( caster, 1 )
                    else
                        call SetUnitAnimationByIndex( caster, 2 )
                    endif
                endif
                set moveAngle = AngleBetweenUnits( caster, target )*bj_DEGTORAD
                call SetUnitFacing( caster, moveAngle*bj_RADTODEG )
                set PolarProjectionX = casterX + moveReal*Cos(moveAngle)
                set PolarProjectionY = casterY + moveReal*Sin(moveAngle)
                call SetUnitX( caster, PolarProjectionX )
                call SetUnitY( caster, PolarProjectionY )
                call SetUnitX( dummy, GetUnitX(target) )
                call SetUnitY( dummy, GetUnitY(target) )
                call SaveReal( udg_dotaHash, trgH, 23, (PolarProjectionX)*1.0 )
                call SaveReal( udg_dotaHash, trgH, 24, (PolarProjectionY)*1.0 )
                set group_NotBash = LoadGroupHandle( udg_dotaHash, trgH, 187 )
                set g = GetGroup()
                set global_caster = caster
                set darkness_caster = caster
                call GroupEnumUnitsInRange( g, PolarProjectionX, PolarProjectionY, 325, Condition(function CheckUnit) )
                set darkness_abilityLvl = abilityLvl
                call ForGroup( g, function ChargeOfDarkness_Bash )
                call RecycleGroup( g )
                set g = null
                if distanceBetweenCasterAndTarget < 3000 and GetUnitAbilityLevel( target, ChargeOfDarknessAddBuff ) == 0 then
                endif
            endif
        endif
        
        set trg    = null
        set caster = null
        set target = null
        set dummy  = null
        
        return false
    endfunction

    private function ChargeOfDarkness_Actions takes nothing returns nothing
        //Старт способности ChargeOfDarkness
        local trigger trg          = CreateTrigger()
        local integer trgH         = GetHandleId( trg )
        local unit    caster       = GetTriggerUnit()
        local unit    target       = GetSpellTargetUnit()
        local unit    dummy        = CreateUnit( GetOwningPlayer(caster), VisionDummy, GetUnitX(target), GetUnitY(target), 0 )
        local integer abilityLvl   = GetUnitAbilityLevel( caster, ChargeOfDarknessAbility )
        local string  effectString = ""
        
        call AddAbility( caster, SwapAbilityContainer )
        call SetPlayerAbilityAvailable( GetOwningPlayer(caster), SwapAbilityContainer, false )

        call AddAbility( caster, Cooldown )
        
        if IsPlayerAlly( GetLocalPlayer(), GetOwningPlayer(caster) ) then
            set effectString = "Abilities\\Spells\\Other\\HowlOfTerror\\HowlTarget.mdl"
            call PingMinimapEx( GetUnitX(target), GetUnitY(target), 2, 255, 255, 255, false )
        endif
        
        call IssueTargetOrder( caster, "move", target )
        call SetUnitPathing( caster, false )
        
        //Здесь нужно настраивать для моделей номер анимации Walk
        //У Rubick это 1
        //У Barathrum это 2
        if GetUnitTypeId( caster ) == GrandMagus then
            call SetUnitAnimationByIndex( caster, 1 )
        else
            call SetUnitAnimationByIndex( caster, 2 )
        endif
        
        call SetUnitTimeScale( caster, 2.5 )
        call SetPlayerAbilityAvailable( GetOwningPlayer(caster), SpellImmunity, false )
        call SetUnitVertexColor( caster, 255, 255, 255, 100 )
        
        call SaveUnitHandle  ( udg_dotaHash, trgH, 2   , caster                                                                                )
        call SaveUnitHandle  ( udg_dotaHash, trgH, 17  , target                                                                                )
        call SaveUnitHandle  ( udg_dotaHash, trgH, 19  , dummy                                                                                 )
        call SaveInteger     ( udg_dotaHash, trgH, 5   , abilityLvl                                                                            )
        call SaveReal        ( udg_dotaHash, trgH, 442 ,(TimerGetElapsed(udg_dotaTimer)+50)*1.0                                                )
        call SaveReal        ( udg_dotaHash, trgH, 23  , GetUnitX(caster)*1.0                                                                  )
        call SaveReal        ( udg_dotaHash, trgH, 24  , GetUnitY(caster)*1.0                                                                  )
        call SaveEffectHandle( udg_dotaHash, trgH, 175 , AddSpecialEffectTarget(effectString,target,"overhead")                                )
        call SaveEffectHandle( udg_dotaHash, trgH, 176 , AddSpecialEffectTarget(effectString,target,"overhead")                                )
        call SaveEffectHandle( udg_dotaHash, trgH, 177 , AddSpecialEffectTarget("war3mapImported\\ShockwaveMissilePurple.mdx",caster,"origin") )
        call SaveGroupHandle ( udg_dotaHash, trgH, 187 , GetGroup()                                                                            )
        
        call TriggerRegisterTimerEvent( trg, 0.02, true                             )
        call TriggerRegisterDeathEvent( trg, caster                                 )
        call TriggerRegisterDeathEvent( trg, target                                 )
        call TriggerRegisterUnitEvent ( trg, caster, EVENT_UNIT_ISSUED_ORDER        )
        call TriggerRegisterUnitEvent ( trg, caster, EVENT_UNIT_ISSUED_POINT_ORDER  )
        call TriggerRegisterUnitEvent ( trg, caster, EVENT_UNIT_ISSUED_TARGET_ORDER )
        call TriggerAddCondition( trg, Condition(function ChargeOfDarkness_Move) )
        
        set trg    = null
        set caster = null
        set target = null
        set dummy  = null
    endfunction

    private function ChargeOfDarkness_Conditions takes nothing returns boolean
        if GetSpellAbilityId() == ChargeOfDarknessAbility and BlockAbility( GetSpellTargetUnit() ) == false then
            call ChargeOfDarkness_Actions()
        elseif GetSpellAbilityId() == ChargeOfDarknessAbility then
            call IssueImmediateOrder( GetTriggerUnit(), "stop" )
        endif
        
        return false
    endfunction

    private function InitChargeOfDarkness takes nothing returns nothing
        local trigger trg = CreateTrigger()
        
        call AnyUnitEvent( trg, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition( trg, Condition(function ChargeOfDarkness_Conditions) )
        
        call AbilityInit( Generic_Stun )
    endfunction
    
endlibrary
NetherStrike
library NetherStrike initializer InitNetherStrike requires OtherFunctions, GreaterBash
    
    
    globals
        
        private unit strike_caster = null
        
        define
            SpellImmunity       = 'A179' //Spell Immunity
            NetherStrikeAbility = 'A0G4' //Nether Strike
            NetherStrikeUpgrade = 'A1D8' //Nether Strike Upgrade
        enddefine
        
    endglobals
    
    
    private function NetherStrike_Bash takes unit caster, unit target returns nothing
        //Вызывает GreaterBash
        local trigger trg
        local integer trgH
        local real    angle = Atan2( GetUnitY(target)-GetUnitY(caster), GetUnitX(target)-GetUnitX(caster) )
        local integer i     = 4
    
        call GreaterBash( caster, target, true, true )
    
        set trg = null
    endfunction

    private function BashForGroup takes nothing returns nothing
        call NetherStrike_Bash( strike_caster, GetEnumUnit() )
    endfunction

    private function NetherStrike_AlternativeBash takes unit caster, unit target returns nothing
        //Используется только если уровень NetherStrike равен 0
        local group g = GetGroup()
    
        set global_caster = caster
        set strike_caster = caster
        call GroupEnumUnitsInRange( g, GetUnitX(caster), GetUnitY(caster), 275, Condition(function CheckUnit) )
        call ForGroup( g, function BashForGroup )
        call RecycleGroup( g )
    
        set g = null
    endfunction

    private function NetherStrike_Move takes nothing returns boolean
        //Используется для прыжка кастера
        local trigger trg             = GetTriggeringTrigger()
        local integer trgH            = GetHandleId( trg )
        local unit    caster          = LoadUnitHandle( udg_dotaHash, trgH, 2 )
        local unit    target          = LoadUnitHandle( udg_dotaHash, trgH, 17 )
        local integer trgCount        = GetTriggerEvalCount( trg )
        local integer alpha
        local integer abilityLvl
        local real    angle
        local real    targetX         = LoadReal( udg_dotaHash, trgH, 23 )
        local real    targetY         = LoadReal( udg_dotaHash, trgH, 24 )
        local real    current_targetX = GetUnitX( target )
        local real    current_targetY = GetUnitY( target )
        local real    distance        = DistanceBetweenCoordinates( current_targetX, current_targetY, targetX, targetY )
        
        call SaveReal( udg_dotaHash, trgH, 23, current_targetX*1.0 )
        call SaveReal( udg_dotaHash, trgH, 24, current_targetY*1.0 )
        
        if GetTriggerEventId() == EVENT_UNIT_DEATH or trgCount == 200 or distance > 1800 then
            //Отменяет способность если target или caster умирают. Или если расстояние между ними становится больше 1800
            //Или если прошло 0.1 секунды с момента прыжка
            call SetUnitVertexColor( caster, 255, 255, 255, 255 )
            call UnitShareVision( target, GetOwningPlayer(caster), false )
            call UnitRemoveAbility( caster, SpellImmunity )
            call FlushChildHashtable( udg_dotaHash, trgH )
            call DestroyTriggerEx( trg )
        else
            //Меняет прозрачность юнита из расчета на кол-во срабатываний триггера
            if trgCount < 100 then
                set alpha = trgCount
            else
                set alpha = 200-trgCount
            endif
            call SetUnitVertexColor( caster, 255, 255, 255, 255*(100-alpha)/100 )
            if trgCount == 100 then
                //Прыжок юнита
                set abilityLvl = LoadInteger( udg_dotaHash, trgH, 5 )
                set angle = Atan2( GetUnitY(target)-GetUnitY(caster), GetUnitX(target)-GetUnitX(caster) )
                call SetUnitPosition( caster, GetUnitX(target)+80*Cos(angle), GetUnitY(target)+80*Sin(angle) )
                call SetUnitAnimation( caster, "attack" )
                call IssueTargetOrder( caster, "attack", target )
                if GetUnitAbilityLevel( caster, NetherStrikeAbility ) > 0 then
                    call NetherStrike_Bash( caster, target )
                else
                    call NetherStrike_AlternativeBash( caster, target )
                endif
                call DamageToUnit( caster, target, 1, 50+100*abilityLvl )
            endif
        endif
        
        set trg    = null
        set caster = null
        set target = null
        
        return false
    endfunction

    private function NetherStrike_Start takes nothing returns nothing
        //Срабатывает спустя время подготовки заклинания
        local trigger trg        = CreateTrigger()
        local integer trgH       = GetHandleId( trg )
        local unit    caster     = GetTriggerUnit()
        local unit    target     = GetSpellTargetUnit()
        local integer abilityLvl = GetUnitAbilityLevel( caster, NetherStrikeAbility )
        
        if abilityLvl == 0 then
            set abilityLvl = GetUnitAbilityLevel( caster, NetherStrikeUpgrade )
        endif
        
        call UnitShareVision( target, GetOwningPlayer(caster), true )
        call IssueImmediateOrder( caster, "halt" )
        call SaveUnitHandle( udg_dotaHash, trgH, 2  , caster               )
        call SaveUnitHandle( udg_dotaHash, trgH, 17 , target               )
        call SaveInteger   ( udg_dotaHash, trgH, 5  , abilityLvl           )
        call SaveReal      ( udg_dotaHash, trgH, 23 , GetUnitX(target)*1.0 )
        call SaveReal      ( udg_dotaHash, trgH, 24 , GetUnitY(target)*1.0 )
        call TriggerRegisterTimerEvent( trg, 0.001, true )
        call TriggerRegisterUnitEvent( trg, caster, EVENT_UNIT_DEATH )
        call TriggerRegisterUnitEvent( trg, target, EVENT_UNIT_DEATH )
        call TriggerAddCondition( trg, Condition(function NetherStrike_Move) )
        call SetPlayerAbilityAvailable( GetOwningPlayer(caster), SpellImmunity, false )
        
        set trg    = null
        set caster = null
        set target = null
    endfunction

    private function PlayAnimation takes nothing returns boolean
        //Проигрывание анимации
        local trigger trg    = GetTriggeringTrigger()
        local integer trgH   = GetHandleId( trg )
        local unit    caster = LoadUnitHandle( udg_dotaHash, trgH, 2 )
        
        call SetUnitAnimation( caster, "spell morph" )
        call FlushChildHashtable( udg_dotaHash, trgH )
        
        call DestroyTriggerEx( trg )
        
        set trg    = null
        set caster = null
        
        return false
    endfunction

    private function ShareVision takes nothing returns boolean
        local trigger trg    = GetTriggeringTrigger()
        local integer trgH   = GetHandleId( trg )
        local unit    caster = LoadUnitHandle( udg_dotaHash, trgH, 2  )
        local unit    target = LoadUnitHandle( udg_dotaHash, trgH, 17 )
        
        call UnitShareVision( target, GetOwningPlayer(caster), false )
        call FlushChildHashtable( udg_dotaHash, trgH )
        call DestroyTriggerEx( trg )

        
        set trg    = null
        set caster = null
        set target = null
        
        return false
    endfunction
    
    private function NetherStrike_Channel takes nothing returns nothing
        //Срабатывает когда кастер нажимает способность на цель
        local trigger trg    = CreateTrigger()
        local integer trgH   = GetHandleId(trg)
        local unit    caster = GetTriggerUnit()
        
        call SaveUnitHandle( udg_dotaHash, trgH, 2, caster )
        call TriggerRegisterTimerEvent( trg, 0., true )
        call TriggerAddCondition( trg, Condition(function PlayAnimation) )
        set trg  = CreateTrigger()
        set trgH = GetHandleId( trg )
        call SaveUnitHandle( udg_dotaHash, trgH, 2, caster )
        call SaveUnitHandle( udg_dotaHash, trgH, 17, GetSpellTargetUnit() )
        call TriggerRegisterTimerEvent( trg, 1., true )
        call TriggerAddCondition( trg, Condition(function ShareVision) )
        call UnitShareVision( GetSpellTargetUnit(), GetOwningPlayer(caster), true )
        
        set trg    = null
        set caster = null
    endfunction

    private function NetherStrike_Conditions takes nothing returns boolean
        if GetSpellAbilityId() == NetherStrikeAbility or GetSpellAbilityId() == NetherStrikeUpgrade then
            if BlockAbility(GetSpellTargetUnit()) == false then
                if GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_EFFECT then
                    call NetherStrike_Start()
                elseif GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_CHANNEL then
                    call NetherStrike_Channel()
                else
                    call IssueImmediateOrder( GetTriggerUnit(), "stop" )
                endif
            endif
        endif
        
        return false
    endfunction
    
    private function InitNetherStrike takes nothing returns nothing
        local trigger trg = CreateTrigger()
        
        call AnyUnitEvent( trg, EVENT_PLAYER_UNIT_SPELL_EFFECT  )
        call AnyUnitEvent( trg, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
        call AnyUnitEvent( trg, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
        call TriggerAddCondition( trg, Condition(function NetherStrike_Conditions) )
        
        set trg = null
    endfunction


endlibrary
EmpoweringHaste
library EmpoweringHaste initializer InitEmpoweringHaste requires OtherFunctions
    
    
    define
    
        EmpoweringHasteAbility = 'A004' //Empowering Haste
        EmpoweringHasteNormal  = 'A30W' //Empowering Haste Container - Normal
        EmpoweringHasteStrong  = 'A30H' //Empowering Haste Container - Strong
        EmpoweringHasteWeak    = 'A30P' //Empowering Haste Container - Weak
    
    enddefine
    
    
    private function EmpoweringHaste_Normal takes nothing returns boolean
        //Возвращение в нормальную скорость перемещения
        local trigger trg        = GetTriggeringTrigger()
        local integer trgH       = GetHandleId( trg )
        local unit    caster     = LoadUnitHandle( udg_dotaHash, trgH, 2 )
        local integer abilityLvl = GetUnitAbilityLevel( caster, EmpoweringHasteAbility )
    
        call UnitRemoveAbility( caster, EmpoweringHasteNormal )
        call UnitRemoveAbility( caster, EmpoweringHasteWeak )
        call AddAbility( caster, EmpoweringHasteNormal )
        call SetUnitAbilityLevel( caster, EmpoweringHasteNormal,abilityLvl )
        call FlushChildHashtable( udg_dotaHash, trgH )
        call DestroyTriggerEx( trg )
    
        set trg    = null
        set caster = null
    
        return false
    endfunction

    private function EmpoweringHaste_Weak takes nothing returns boolean
        //Изменение скорости на минимальную скорость перемещения
        local trigger trg        = GetTriggeringTrigger()
        local integer trgH       = GetHandleId( trg )
        local unit    caster     = LoadUnitHandle( udg_dotaHash, trgH, 2 )
        local integer abilityLvl = GetUnitAbilityLevel( caster, EmpoweringHasteAbility )
    
        call UnitRemoveAbility( caster, EmpoweringHasteNormal )
        call UnitRemoveAbility( caster, EmpoweringHasteStrong )
        call AddAbility( caster, EmpoweringHasteWeak )
        call SetUnitAbilityLevel( caster, EmpoweringHasteWeak, abilityLvl )
        call FlushChildHashtable( udg_dotaHash, trgH )
        call DestroyTriggerEx( trg )
        set trg  = CreateTrigger()
        set trgH = GetHandleId( trg )
        call TriggerRegisterTimerEvent( trg, 10, false )
        call TriggerAddCondition( trg, Condition(function EmpoweringHaste_Normal) )
        call SaveUnitHandle( udg_dotaHash, trgH, 2, caster )
    
        set trg    = null
        set caster = null
    
        return false
    endfunction

    private function EmpoweringHaste_Actions takes nothing returns nothing
        //Изменение скорости на максимальную скорость перемещения
        local trigger trg        = CreateTrigger()
        local integer trgH       = GetHandleId( trg )
        local unit    caster     = GetTriggerUnit()
        local integer abilityLvl = GetUnitAbilityLevel( caster, EmpoweringHasteAbility )
        
        call TriggerRegisterTimerEvent( trg, 6, false )
        call TriggerAddCondition( trg, Condition(function EmpoweringHaste_Weak) )
        call SaveUnitHandle( udg_dotaHash, trgH, 2, caster )
        call UnitRemoveAbility( caster, EmpoweringHasteNormal )
        call UnitRemoveAbility( caster, EmpoweringHasteWeak )
        call AddAbility( caster, EmpoweringHasteStrong )
        call SetUnitAbilityLevel( caster, EmpoweringHasteStrong, abilityLvl )
    
        set trg    = null
        set caster = null
    endfunction

    private function EmpoweringHaste_Conditions takes nothing returns boolean
        if GetSpellAbilityId() == EmpoweringHasteAbility then
            call EmpoweringHaste_Actions()
        endif
    
        return false
    endfunction

    private function PermanentBonus_Actions takes nothing returns nothing
        //Получение постоянного бонуса при изучении EmpoweringHaste
        local integer abilityLvl = GetUnitAbilityLevel( GetTriggerUnit(), EmpoweringHasteAbility )
    
        call SetPlayerAbilityAvailable( GetOwningPlayer(GetTriggerUnit()), EmpoweringHasteStrong, false )
        call SetPlayerAbilityAvailable( GetOwningPlayer(GetTriggerUnit()), EmpoweringHasteNormal, false )
        call SetPlayerAbilityAvailable( GetOwningPlayer(GetTriggerUnit()), EmpoweringHasteWeak, false )
        call AddAbility( GetTriggerUnit(), EmpoweringHasteNormal )
        call SetUnitAbilityLevel( GetTriggerUnit(), EmpoweringHasteNormal, abilityLvl )
    endfunction

    private function PermanentBonus_Conditions takes nothing returns boolean
        if GetLearnedSkill() == EmpoweringHasteAbility and IsUnitIllusion(GetTriggerUnit()) == false then
            call PermanentBonus_Actions()
        endif
    
        return false
    endfunction

    private function InitEmpoweringHaste takes nothing returns nothing
        local trigger trg = CreateTrigger()
    
        call AnyUnitEvent( trg, EVENT_PLAYER_HERO_SKILL )
        call TriggerAddCondition( trg, Condition(function PermanentBonus_Conditions) )
        set trg = CreateTrigger()
        call AnyUnitEvent( trg, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition( trg, Condition(function EmpoweringHaste_Conditions) )
    
        set trg = null
    endfunction
    

endlibrary
GreaterBash
library GreaterBash initializer InitGreaterBash requires OtherFunctions

    
    define
        
        trgTime = 3 //Время удаления временного бонуса к скорости, который дается при срабатывании GreaterBash
        
        SpiritbashContainer = 'A24H' //Spiritbash Container
        SpiritbashBuff      = 'B0EC' //Spiritbash
        GreaterBashAbility  = 'A0G5' //Greater Bash
        Spellcaster         = 'e00E' //Spellcaster
        GreaterBashStun     = 'A1WQ' //Greater Bash Stun
        
    enddefine


    private function SpeedBonusRemove takes nothing returns boolean
        //Удаляет бонус к скорости
        local trigger trg      = GetTriggeringTrigger()
        local integer trgH     = GetHandleId( trg )
        local unit    attacker = LoadUnitHandle( udg_dotaHash, trgH, 2 )
        local real    time     = LoadReal( udg_dotaHash, GetHandleId(attacker), 685 )
        
        call FlushChildHashtable( udg_dotaHash, trgH )
        call DestroyTriggerEx( trg )
        if time < TimerGetElapsed(udg_dotaTimer) or GetTriggerEventId() == EVENT_WIDGET_DEATH then
            call SaveReal( udg_dotaHash, GetHandleId(attacker), 685, 0*1.0 )
            call UnitRemoveAbility( attacker, SpiritbashContainer )
            call UnitRemoveAbility( attacker, SpiritbashBuff )
        endif
    
        set trg      = null
        set attacker = null
    
        return false
    endfunction

    private function SpeedBonus takes unit u returns nothing
        //Добавляет бонус к скорости после срабатывания GreaterBash
        local trigger trg  = CreateTrigger()
        local integer trgH = GetHandleId( trg )
    
        call AddAbility( u, SpiritbashContainer )
        call SetPlayerAbilityAvailable( GetOwningPlayer(u), SpiritbashContainer, false )
        call SaveReal( udg_dotaHash, GetHandleId(u), 685, (TimerGetElapsed(udg_dotaTimer)+trgTime-0.01)*1.0)
        call TriggerRegisterTimerEvent( trg, trgTime, false )
        call TriggerRegisterDeathEvent( trg, u )
        call TriggerAddCondition( trg, Condition(function SpeedBonusRemove) )
        call SaveUnitHandle( udg_dotaHash, trgH, 2, u )
    
        set trg = null
    endfunction

    private function GreaterBash_Actions takes nothing returns boolean
        //Отталкивание юнита
        local trigger trg      = GetTriggeringTrigger()
        local integer trgH     = GetHandleId( trg )
        local unit    target   = LoadUnitHandle( udg_dotaHash, trgH, 17 )
        local unit    attacker = LoadUnitHandle( udg_dotaHash, trgH, 2 )
        local real    angle    = LoadReal( udg_dotaHash, trgH, 13 )
        local real    x        = GetUnitX( target )
        local real    y        = GetUnitY( target )
        local integer trgCount = GetTriggerEvalCount( trg )
        local real    r        = LoadReal( udg_dotaHash, trgH, 193 )
        local integer i        = LoadInteger( udg_dotaHash, trgH, 12 )
    
        if trgCount > 35 then
            call SaveReal( udg_dotaHash, trgH, 193, (r*0.98)*1.0 )
        endif
        if GetTriggerEventId() == EVENT_UNIT_DEATH or trgCount > i then
            call FlushChildHashtable( udg_dotaHash, trgH )
            call DestroyTriggerEx( trg )
        else
            call DestroyEffect( AddSpecialEffect("Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl", x, y) )
            call KillDestructables( x, y, 150 )
            set x = SafeRealX( x+r*Cos(angle) )
            set y = SafeRealY( y+r*Sin(angle) )
            if IsPointInRegion(global_region, x*1.0, y*1.0) == false then
                call SetUnitX( target, x )
                call SetUnitY( target, y )
            endif
            if trgCount == 1 and LoadBoolean(udg_dotaHash, trgH, 698) == false then
                call IssueTargetOrder( attacker, "attack", target )
            endif
        endif
    
        set trg      = null
        set target   = null
        set attacker = null
    
        return false
    endfunction

    function GreaterBash takes unit attacker, unit target, boolean b, boolean off returns nothing
        local trigger trg
        local integer trgH
        local real    angle      = Atan2( GetUnitY(target)-GetUnitY(attacker), GetUnitX(target)-GetUnitX(attacker) )
        local integer abilityLvl = GetUnitAbilityLevel( attacker, GreaterBashAbility )
        local unit    dummy
    
        if b then
        endif
        //Здесь нужно указывать все способности или бафы, имея которые не будет срабатывать GreaterBash
        //Оригинал:
        //if abilityLvl > 0 and GetUnitAbilityLevel(attacker, 'BNdo') == 0 then
        if abilityLvl > 0 then
            set dummy = CreateUnit( GetOwningPlayer(target), Spellcaster, GetUnitX(target), GetUnitY(target), 0 )
            call AddAbility( dummy, GreaterBashStun )
            call SetUnitAbilityLevel( dummy, GreaterBashStun, abilityLvl )
            if IssueTargetOrder( dummy, "thunderbolt", target ) then
                //Если можно кинуть стан на цель, значит сработает отталкивание юнита
                set trg  = CreateTrigger()
                set trgH = GetHandleId( trg )
                call DestroyEffect( AddSpecialEffectTarget("Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl", attacker, "weapon") )
                call SaveUnitHandle( udg_dotaHash, trgH, 2   , attacker         )
                call SaveUnitHandle( udg_dotaHash, trgH, 17  , target           )
                call SaveReal      ( udg_dotaHash, trgH, 13  , angle*1.0        )
                call SaveReal      ( udg_dotaHash, trgH, 193 , 2*1.0            )
                call SaveBoolean   ( udg_dotaHash, trgH, 698 , off              )
                call SaveInteger   ( udg_dotaHash, trgH, 12  , 80+20*abilityLvl )
                call TriggerRegisterUnitEvent( trg,target, EVENT_UNIT_DEATH )
                call TriggerRegisterTimerEvent( trg, 0.01, true)
                call TriggerAddCondition( trg, Condition(function GreaterBash_Actions) )
                call DamageToUnit( attacker, target, 1, GetUnitMoveSpeed(attacker)*(0.16+0.06*abilityLvl) )
                call SpeedBonus( attacker )
            endif
            if off == false then
                call BashOff( attacker, 4276, 1.5 )
            endif
        endif
    
        set trg      = null
        set attacker = null
        set target   = null
        set dummy    = null
    endfunction

    private function GreaterBash_Conditions takes nothing returns boolean
        //Здесь дополнительная проверка чтобы GreaterBash при атаке не срабатывал повторно в течении 1.5 секунды
        if GetUnitAbilityLevel(GetAttacker(), GreaterBashAbility) > 0 and IsUnitIllusion(GetAttacker()) == false and IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE) == false and IsUnitEnemy(GetTriggerUnit(), GetOwningPlayer(GetAttacker()))and GetRandomInt(1, 100) <= 17 and ( LoadInteger(udg_dotaHash,GetHandleId(GetAttacker()), 4276) == 1 ) == false then
            call GreaterBash( GetAttacker(), GetTriggerUnit(), false, false )
        endif
    
        return false
    endfunction

    private function InitGreaterBash takes nothing returns nothing
        local trigger trg = CreateTrigger()
    
        call AnyUnitEvent( trg, EVENT_PLAYER_UNIT_ATTACKED )
        call TriggerAddCondition( trg, Condition(function GreaterBash_Conditions) )
    
        set trg = null
    endfunction


endlibrary
`
ОЖИДАНИЕ РЕКЛАМЫ...
0
28
6 лет назад
0
UrsaBoss, переделывай
хотя как по мне проще будет написать с 0
и я бы триггеры заменил на таймеры
и раз юзаешь cjass то юзай его полностью
а то гдето есть, гдето нету
если ктото захочет дать эти абилки многим юнитам то будет ппц
думаю даже при 100 юнитах будут лаги
0
18
6 лет назад
0
nvc123:
и раз юзаешь cjass то юзай его полностью
а то гдето есть, гдето нету
просто у cJass define удобный очень)
0
21
6 лет назад
0
quq_CCCP, хз, ирония это или нет, плохо помню сларка в доте 1
ладно, мне просто влом внимательно изучать триги, если там такая система, что работает просто замена ивента, чтобы только на атаку все равно срабатывало - ок
0
18
6 лет назад
Отредактирован Hodor
0
nvc123:
если ктото захочет дать эти абилки многим юнитам то будет ппц
думаю даже при 100 юнитах будут лаги
когда бара бежит GreaterBash на юнитов по пути тоже лаги вызывает, особенно когда пробегаешь через кучу юнитов, то ваще до 20-30 просадка
0
28
6 лет назад
0
UrsaBoss, только что оформил ресурс с системой которая немного поможет в оптимизации
только на этих 2 активных способностях правда будет не особо видно но если в карте более 100 активных способностей то результат заметен невооружённым глазом
0
18
6 лет назад
Отредактирован Hodor
0
quq_CCCP а можно же вместо щита маны сделать вторую пустышку с вечным кд, а чтобы запустить кд - отдать приказ кастовать пустышку без цели?
0
32
6 лет назад
0
У тебя нет надежного запуска кд без мемхака, увы...
0
18
6 лет назад
Отредактирован Hodor
0
quq_CCCP:
Кнопку ауры бы сделал из веера ножей, бара встает и танцует при касте усилялки ауры, что нафиг ненужно
вот только сейчас заметил что она и так сделана на основе веерного броска
quq_CCCP короче, сделал по своему с EmpoweringHaste, взял за основу способность "Берсерк", скопипастил все параметры, длительность на 0.01 и работает, приказ не сбивает, бара не танцует
починил ChargeOfDarkness по той инструкции, теперь можно изучать способность прямо во время разбега.
не совсем понял что с NetherStrike, там просто добавить отмену каста способности если юнит получил стан?
0
32
6 лет назад
0
В том числе, а еще если жертва убежит, бара как идиот идет догонять и не стопится...
0
18
6 лет назад
Отредактирован Hodor
0
quq_CCCP:
В том числе, а еще если жертва убежит, бара как идиот идет догонять и не стопится...
починил с помощью SPELL_ENDCAST
Обновил ресурс
0
32
6 лет назад
0
Берсерк кстати не сочитается с другими берсерками, неважно какой длиннее или кто дает бонусов выше, который был активирован последним тот и будет работать, а в доте есть mask of madness, которая основана как раз на берсерке, собьет... Юзай виндвалк.
0
18
6 лет назад
0
quq_CCCP:
Берсерк кстати не сочитается с другими берсерками, неважно какой длиннее или кто дает бонусов выше, который был активирован последним тот и будет работать, а в доте есть mask of madness, которая основана как раз на берсерке, собьет... Юзай виндвалк.
а фазы не будет сбивать? Я время входа на -1 поставил и длительность на 0.01
точнее бонус к скорости от фаз
0
32
6 лет назад
0
UrsaBoss, будет, любые скиллы при касте сбивайют фейзы, но это лечится вручением руны с виндвалком. У фрога все через жопу, хотя была сравнительно простая возможность пофиксить такую кучу багов и недоработок.
0
21
6 лет назад
0
уставал человек
Чтобы оставить комментарий, пожалуйста, войдите на сайт.