28

» WarCraft 3 / Заклинания на заказ

nazarpunk, мб когда апи с прожектайлами починятся и дополнятся, то сделаю заказы с копированием снарядов, сейчас каждый раз на грабли натыкаюсь и тильтую
28

» WarCraft 3 / Как сделать MUI через глобалки? - [Jass]

Демонстрация работ

Код

Untitled Trigger 001
globals
    constant timer TempTimer = CreateTimer( )
    constant group TempGroup = CreateGroup( )
    
    integer max = 0
    
    unit array caster
    unit array dummy
    
    player array owningPlayer
    group array g
    
    real array x
    real array y
    real array angleX
    real array angleY
    real array radius
    real array speed
    real array distance
endglobals

native UnitAlive takes unit id returns boolean

function Move takes nothing returns nothing
    local integer i = 1
    local unit u
    
    loop
        exitwhen i > max
        
        if speed[i] > distance[i] then
            set speed[i] = distance[i]
        endif
        
        set x[i] = x[i] + speed[i] * angleX[i]
        set y[i] = y[i] + speed[i] * angleY[i]
        
        call SetUnitX( dummy[i], x[i] )
        call SetUnitY( dummy[i], y[i] )
        call DestroyEffect( AddSpecialEffect( "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", x[i], y[i] ) )
        
        call GroupEnumUnitsInRange( TempGroup, x[i], y[i], radius[i] + 200.00, null )
        
        loop
            set u = FirstOfGroup( TempGroup )
            exitwhen u == null
            call GroupRemoveUnit( TempGroup, u )
            
            if IsUnitInRangeXY( u, x[i], y[i], radius[i] ) then
                if not IsUnitInGroup( u, g[i] ) then
                    if UnitAlive( u ) and IsUnitEnemy( u, owningPlayer[i] ) then
                        call GroupAddUnit( g[i], u )
                        call UnitDamageTarget( caster[i], u, 100.00, false, false, null, null, null )
                    endif
                endif
            endif
        endloop
        
        set distance[i] = distance[i] - speed[i]
        
        if distance[i] <= 0.00 then
            call KillUnit( dummy[i] )
            
            call DestroyGroup( g[i] )
            
            set caster[i] = caster[max]
            set dummy[i] = dummy[max]
            set owningPlayer[i] = owningPlayer[max]
            set g[i] = g[max]
            set x[i] = x[max]
            set y[i] = y[max]
            set angleX[i] = angleX[max]
            set angleY[i] = angleY[max]
            set radius[i] = radius[max]
            set speed[i] = speed[max]
            set distance[i] = distance[max]
            
            set max = max - 1
            set i = i - 1
            
            if max <= 0 then
                call PauseTimer( TempTimer )
            endif
        endif
        
        set i = i + 1
    endloop
endfunction

function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
    local real a
    
    if max == 0 then
        call TimerStart( TempTimer, 0.03125, true, function Move )
    endif
    
    set max = max + 1
    
    set caster[max] = GetTriggerUnit( )
    set owningPlayer[max] = GetOwningPlayer( caster[max] )
    
    set g[max] = CreateGroup( )
    
    set x[max] = GetUnitX( caster[max] )
    set y[max] = GetUnitY( caster[max] )
    
    set a = Atan2( GetSpellTargetY( ) - y[max], GetSpellTargetX( ) - x[max] )
    
    set angleX[max] = Cos( a )
    set angleY[max] = Sin( a )
    
    set dummy[max] = CreateUnit( owningPlayer[max], 'h000', x[max], y[max], a * bj_RADTODEG )
    
    set radius[max] = 200.00
    set speed[max] = 1000.00 * 0.03125
    set distance[max] = 1000.00
endfunction

//===========================================================================
function InitTrig_Untitled_Trigger_001 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_001 = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Untitled_Trigger_001, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( gg_trg_Untitled_Trigger_001, function Trig_Untitled_Trigger_001_Actions )
endfunction

можешь в следующий раз по подобным спеллмейкерским вопросам обратиться в мою тему

а, я так понимаю там сама идея была в том, что огненный шар дамажит всё время при движении, а не один раз - достаточно тогда просто удалить всё, что связанно с переменной g
Загруженные файлы
28

» WarCraft 3 / Как сделать MUI через глобалки? - [Jass]

LastUchiha, какой-то ужас
я конечно понимаю что ты хотел на чистом джассе реализовать с глобалками, но хэштаблица со структурами будет удобнее, тем более, ты уже юзаешь вджасс
твои массивы на глобалках нужны разве что в гуишном варианте
Загруженные файлы
28

» WarCraft 3 / Заклинания на заказ

Выполнение заказа

Заклинание готово!

я немного не понял нужен ли учёт сферических координат, если корабль только по наземным должен дамажить, поэтому просто пихнул проверку, что юнит не летающий
на видосе 100% шанс срабатывания, пассивка срабатывает после получения урона противником, могу переделать под старт вылета снаряда либо при замахе
инструкция по импорту
скопировать папку Initialization и вставить в свою карту
в триггере DamageEvent:
78 строка - указать абилку и шанс такой атаки (абилку выдать юнитам, что должны проводить эту атаку)
85 строка - начальный оффсет угла от взгляда атакующего
86 строка - скорость вращения лазеров
93 строка - через сколько секунд появляются лазеры после начала проигрывания анимки Spell Slam
21-24 строки - оффсеты для лазеров
30 строка - радиус вокруг атакующего
38 строка - ширина лазера (32.00)
47, 49-52 строки - шаг лазера (чем больше тем менее точно, но более оптимизировано, лучше не ставить больше радиуса лазера)
48 строка - дальность лазера
54-55 - эффекты, использовал по сути как дебаг для ориентации скорости, оффсета и угла лазеров, можно удалить строки
58 - максимальный угол лазеров
71 - периодичность таймера (чем больше, тем оптимизированнее и менее точно, при изменении этой строки на 86 строке (0.05) тоже изменить периодичность)
делал на южапи

Код

AllGlobals
library AllGlobalsLib
globals
    constant hashtable H = InitHashtable( )
    constant real UNIT_MAX_COLLISION = 200.00
endglobals

native UnitAlive takes unit id returns boolean

//===========================================================================
//function InitTrig_AllGlobals takes nothing returns nothing
    //set gg_trg_AllGlobals = CreateTrigger(  )
//endfunction
endlibrary

DamageEvent
library DamageEventLib
globals
    private constant group TempGroup = CreateGroup( )
endglobals

private struct SpellS
    timer t
    unit caster
    player p
    group g
    real angle
    real speed
endstruct

private function Damage takes nothing returns nothing
    local SpellS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local real d = 0.00 
    local real a = GetUnitFacing( A.caster ) * bj_DEGTORAD
    local real x = GetUnitX( A.caster )
    local real y = GetUnitY( A.caster )
    local real x1 = x + 125.00 * Cos( a + bj_PI * 0.30 )
    local real y1 = y + 125.00 * Sin( a + bj_PI * 0.30 )
    local real x2 = x + 125.00 * Cos( a - bj_PI * 0.30 )
    local real y2 = y + 125.00 * Sin( a - bj_PI * 0.30 )
    local unit u
    
    call GroupEnumUnitsInRange( TempGroup, x, y, 400.00 + UNIT_MAX_COLLISION, null )
    
    set A.angle = A.angle + A.speed
    
    loop
        loop
            set u = GroupForEachUnit( TempGroup )
            exitwhen u == null
            
            if not IsUnitInGroup( u, A.g ) then
                if IsUnitInRangeXY( u, x1, y1, 32.00 ) or IsUnitInRangeXY( u, x2, y2, 32.00 )then
                    if UnitAlive( u ) and IsUnitEnemy( u, A.p ) and not IsUnitType( u, UNIT_TYPE_FLYING ) then
                        call GroupAddUnit( A.g, u )
                        call UnitDamageTarget( A.caster, u, 150.00, false, false, null, null, null )
                    endif
                endif
            endif
        endloop
        
        set d = d + 32.00
        exitwhen d >= 200.00
        set x1 = x1 + 32.00 * Cos( a + A.angle )
        set y1 = y1 + 32.00 * Sin( a + A.angle )
        set x2 = x2 + 32.00 * Cos( a - A.angle )
        set y2 = y2 + 32.00 * Sin( a - A.angle )
        
        call DestroyEffect( AddSpecialEffect( "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl", x1, y1 ) )
        call DestroyEffect( AddSpecialEffect( "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl", x2, y2 ) )
    endloop
    
    call GroupClear( TempGroup )
    
    if A.angle * bj_RADTODEG >= 120.00 or not UnitAlive( A.caster ) then
        call PauseTimer( A.t )
        call DestroyTimer( A.t )
        call FlushChildHashtable( H, GetHandleId( A.t ) )
        
        call SetUnitStunned( A.caster, false )
        call DestroyGroup( A.g )
        
        set A.t = null
        set A.g = null
        set A.caster = null
        call A.destroy( )
    else
        call TimerStart( A.t, 0.05, false, function Damage )
    endif
endfunction

private function DamageEvent_Actions takes nothing returns nothing
    local SpellS A
    
    if GetUnitAbilityLevel( GetEventDamageSource( ), 'A000' ) > 0 and GetEventIsAttack( ) and GetRandomInt( 1, 100 ) <= 20 then
        set A = SpellS.create( )
        
        set A.t = CreateTimer( )
        set A.caster = GetEventDamageSource( )
        set A.p = GetOwningPlayer( A.caster )
        set A.g = CreateGroup( )
        set A.angle = 60.00 * bj_DEGTORAD
        set A.speed = 60.00 / 0.75 * 0.05 * bj_DEGTORAD
        
        call SetUnitStunned( A.caster, true )
        call SetUnitAnimation( A.caster, "spell slam" )
        call QueueUnitAnimation( A.caster, "stand" )
        
        call SaveInteger( H, GetHandleId( A.t ), 0, A )
        call TimerStart( A.t, 0.25, false, function Damage )
    endif
endfunction

//===========================================================================
function InitTrig_DamageEvent takes nothing returns nothing
    set gg_trg_DamageEvent = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_DamageEvent, EVENT_PLAYER_UNIT_DAMAGED )
    call TriggerAddAction( gg_trg_DamageEvent, function DamageEvent_Actions )
endfunction
endlibrary

Загруженные файлы
28

» WarCraft 3 / Заклинания на заказ

Выполнение заказа

Заклинание готово!

Божественная призма

инструкция по импорту
скопировать папку Initialization и вставить в свою карту
скопировать даммика и абилку из ро и вставить в свою карту
в триггере Spell:
153 строка - указать равкод абилки
30-32 строки - указать скорость полёта снаряда
60 строка - количество целей для урона/хила после основной
54 строка - хил основной цели
57 строка - урон основной цели
62 строка - радиус с максимальной коллизией у юнита (+200)
71 строка - радиус
103 строка - хил второстепенных целей
105 строка - урон второстепенных целей
заменить 'u000' в коде на своего даммика

Код

Spell
function GetLocZ takes real x, real y returns real
    call MoveLocation( udg_LFZ, x, y )
    return GetLocationZ( udg_LFZ )
endfunction

function Move takes nothing returns nothing
    local timer t = GetExpiredTimer( )
    local integer i = GetHandleId( t )
    local integer k
    local player p
    local unit caster
    local unit target = LoadUnitHandle( udg_H, i, 1 )
    local unit dummy = LoadUnitHandle( udg_H, i, 2 )
    local unit u
    local real x = GetUnitX( dummy )
    local real y = GetUnitY( dummy )
    local real z = LoadReal( udg_H, i, 3 )
    local real x1 = GetUnitX( target )
    local real y1 = GetUnitY( target )
    local real z1 = GetLocZ( x1, y1 ) + GetUnitFlyHeight( target ) + 50.00
    local real ax = x1 - x
    local real ay = y1 - y
    local real az = z1 - z
    local real d = RMaxBJ( 1.00, SquareRoot( ax * ax + ay * ay + az * az ) )
    
    set ax = ax / d
    set ay = ay / d
    set az = az / d
    
    set x = x + 20.00 * ax
    set y = y + 20.00 * ay
    set z = z + 20.00 * az
    
    call SetUnitX( dummy, x )
    call SetUnitY( dummy, y )
    call SetUnitFlyHeight( dummy, z - GetLocZ( x, y ), 0.00 )
    
    if IsUnitInRange( dummy, target, 0.00 ) and SquareRoot( ( z1 - z ) * ( z1 - z ) ) <= 100.00 then
        call SetUnitAnimation( dummy, "death" )
        call UnitApplyTimedLife( dummy, 'BTLF', 2.00 )
        
        set caster = LoadUnitHandle( udg_H, i, 0 )
        set p = GetOwningPlayer( caster )
        
        set k = LoadInteger( udg_H, i, 4 )
        
        call PauseTimer( t )
        call FlushChildHashtable( udg_H, GetHandleId( t ) )
        call DestroyTimer( t )
        
        if k == 1 then
            if IsUnitAlly( target, p ) then
                if not IsUnitType( target, UNIT_TYPE_DEAD ) then
                    call SetWidgetLife( target, GetWidgetLife( target ) + 600.00 )
                endif
            else
                call UnitDamageTarget( caster, target, 400.00, false, false, null, null, null )
            endif
            
            set k = 5
            
            call GroupEnumUnitsInRange( udg_TempGroup, x, y, 700.00, null )
            
            call GroupRemoveUnit( udg_TempGroup, target )
            
            loop
                set u = FirstOfGroup( udg_TempGroup )
                exitwhen u == null
                call GroupRemoveUnit( udg_TempGroup, u )
                
                if IsUnitInRangeXY( u, x, y, 500.00 ) then
                    if not IsUnitType( u, UNIT_TYPE_DEAD ) then
                        if ( IsUnitAlly( target, p ) and not IsUnitAlly( u, p ) ) or ( IsUnitAlly( u, p ) and not IsUnitAlly( target, p ) ) then
                            set t = CreateTimer( )
                            set i = GetHandleId( t )
                            
                            set bj_lastCreatedUnit = CreateUnit( GetOwningPlayer( caster ), 'u000', x, y, Atan2( GetUnitY( u ) - y, GetUnitX( u ) - x ) * bj_RADTODEG )
                            call UnitAddAbility( bj_lastCreatedUnit, 'Arav' )
                            call SetUnitX( bj_lastCreatedUnit, x )
                            call SetUnitY( bj_lastCreatedUnit, y )
                            call SetUnitFlyHeight( bj_lastCreatedUnit, z - GetLocZ( x, y ), 0.00 )
                            call SetUnitAnimation( bj_lastCreatedUnit, "birth" )
                            call QueueUnitAnimation( bj_lastCreatedUnit, "stand" )
                            
                            call SaveUnitHandle( udg_H, i, 0, caster )
                            call SaveUnitHandle( udg_H, i, 1, u )
                            call SaveUnitHandle( udg_H, i, 2, bj_lastCreatedUnit )
                            call SaveReal( udg_H, i, 3, z )
                            call SaveInteger( udg_H, i, 4, 0 )
                            call TimerStart( t, 0.01, true, function Move )
                            
                            set i = i - 1
                            
                            if i <= 0 then
                                call GroupClear( udg_TempGroup )
                            endif
                        endif
                    endif
                endif
            endloop
        else
            if IsUnitAlly( target, GetOwningPlayer( caster ) ) then
                call SetWidgetLife( target, GetWidgetLife( target ) + 300.00 )
            else
                call UnitDamageTarget( caster, target, 190.00, false, false, null, null, null )
            endif
        endif
        
        set caster = null
    else
        call SaveReal( udg_H, i, 3, z )
    endif
    
    set t = null
    set dummy = null
    set target = null
endfunction

function Trig_Spell_Actions takes nothing returns nothing
    local timer t = CreateTimer( )
    local integer i = GetHandleId( t )
    local unit caster = GetTriggerUnit( )
    local unit target = GetSpellTargetUnit( )
    local real x = GetUnitX( caster )
    local real y = GetUnitY( caster )
    local real z = GetUnitFlyHeight( caster ) + 50.00
    
    set bj_lastCreatedUnit = CreateUnit( GetOwningPlayer( caster ), 'u000', x, y, Atan2( GetUnitY( target ) - y, GetUnitX( target ) - x ) * bj_RADTODEG )
    call UnitAddAbility( bj_lastCreatedUnit, 'Arav' )
    call SetUnitX( bj_lastCreatedUnit, x )
    call SetUnitY( bj_lastCreatedUnit, y )
    call SetUnitFlyHeight( bj_lastCreatedUnit, z, 0.00 )
    call SetUnitAnimation( bj_lastCreatedUnit, "birth" )
    call QueueUnitAnimation( bj_lastCreatedUnit, "stand" )
    
    set z = z + GetLocZ( x, y )
    
    call SaveUnitHandle( udg_H, i, 0, caster )
    call SaveUnitHandle( udg_H, i, 1, target )
    call SaveUnitHandle( udg_H, i, 2, bj_lastCreatedUnit )
    call SaveReal( udg_H, i, 3, z )
    call SaveInteger( udg_H, i, 4, 1 )
    call TimerStart( t, 0.01, true, function Move )
    
    set t = null
    set caster = null
    set target = null
endfunction

//===========================================================================
function Trig_Spell_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function InitTrig_Spell takes nothing returns nothing
    set gg_trg_Spell = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Spell, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Spell, Condition( function Trig_Spell_Conditions ) )
    call TriggerAddAction( gg_trg_Spell, function Trig_Spell_Actions )
endfunction
Загруженные файлы
28

» WarCraft 3 / Заклинания на заказ

UndeadFisher, мне кажется дело не в самих функциях, эффекты то создаются, но не отображаются
28

» WarCraft 3 / Заклинания на заказ

UndeadFisher, странно, только сейчас заметил на видосе, что при втором касте не заспавнились эффекты, но я не первый раз встречаю такую проблему, возможно дело в компе либо в самом варе, он не отображает порой эффекты, я из-за этой проблемы даже к даммикам возвращался когда-то, с ними всегда всё корректно было
28

» WarCraft 3 / Заклинания на заказ

Выполнение заказа

Заклинание готово!

инструкция по импорту
удалить триггеры ниже триггера Spell
скопировать папку Initialization и вставить в свою карту
указать равкод абилки на 367 строке триггера Spell
изменить строки 340-344 на свой вкус
всё остальное требует минимальных знаний джасса
сделано на южапи

Код

AllGlobals
library AllGlobalsLib
globals
    constant hashtable H = InitHashtable( )
    constant real UNIT_MAX_COLLISION = 200.00
endglobals

native UnitAlive takes unit id returns boolean

struct vector
    real x
    real y
    real z
    
    method length takes nothing returns real
        return SquareRoot( x * x + y * y + z * z )
    endmethod
    
    method normalize takes nothing returns nothing
        local real l = length( )
        
        if l == 0.00 then
            set l = 1.00
        endif
        
        set x = x / l
        set y = y / l
        set z = z / l
    endmethod
    
    static method create takes real x, real y, real z returns thistype
        local thistype this = thistype.allocate( )
        
        set this.x = x
        set this.y = y
        set this.z = z
        
        return this
    endmethod
endstruct
endlibrary

//===========================================================================
//function InitTrig_AllGlobals takes nothing returns nothing
    //set gg_trg_AllGlobals = CreateTrigger(  )
//endfunction

Spell
library SpellLib
globals
    private constant group TempGroup = CreateGroup( )
endglobals

private struct SpellS
    timer t
    unit caster
    effect e
    player p
    vector v
    vector l
    integer i
    group g
    
    real damage
    real speed
    real distance
    real time
    real radius
    handlelist effectList
    
    attacktype attackType
    damagetype damageType
    weapontype weaponType
endstruct

private function Move takes nothing returns nothing
    local SpellS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    
    if A.speed > A.distance then
        set A.speed = A.distance
    endif
    
    set A.distance = A.distance - A.speed
    
    set A.l.x = A.l.x + A.speed * A.v.x
    set A.l.y = A.l.y + A.speed * A.v.y
    set A.l.z = A.l.z + A.speed * A.v.z
    
    call SetSpecialEffectPositionWithZ( A.e, A.l.x, A.l.y, A.l.z )
    
    if A.distance <= 0.00 or A.l.z <= GetAxisZ( A.l.x, A.l.y ) + 32.00 then
        call PauseTimer( A.t )
        call FlushChildHashtable( H, GetHandleId( A.t ) )
        call DestroyTimer( A.t )
        
        call DestroyEffect( A.e )
        
        if A.i == 1 then
            call SetSpecialEffectVisible( A.e, false )
            
            set A.e = AddSpecialEffect( "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl", A.l.x, A.l.y )
            call SetSpecialEffectZ( A.e, A.l.z )
            call SetSpecialEffectOrientation( A.e, Atan2( A.v.y, A.v.x ) * bj_RADTODEG, 45.00, 0.00 )
            call SetSpecialEffectTimeScale( A.e, 2.00 )
            call DestroyEffect( A.e )
        endif
        
        set A.e = null
        set A.t = null
        call A.l.destroy( )
        call A.v.destroy( )
        call A.destroy( )
    endif
endfunction

private function Damage takes nothing returns nothing
    local SpellS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local unit u
    
    loop
        set u = FirstOfGroup( A.g )
        exitwhen u == null
        call GroupRemoveUnit( A.g, u )
        
        call SetUnitStunned( u, false )
        call SetUnitTimeScale( u, 1.00 )
        call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl", u, "chest" ) )
        
        call UnitDamageTarget( A.caster, u, A.damage, false, false, A.attackType, A.damageType, A.weaponType )
    endloop
    
    call PauseUnit( A.caster, false )
    
    set A.l.z = GetUnitFacing( A.caster ) * bj_DEGTORAD
    set A.l.x = A.l.x + 100.00 * Cos( A.l.z )
    set A.l.y = A.l.y + 100.00 * Sin( A.l.z )
    
    call DestroyEffect( A.e )
    
    set A.e = AddSpecialEffect( "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", A.l.x, A.l.y )
    call DestroyEffect( A.e )
    
    loop
        call DestroyEffect( HandleListGetEffectByIndex( A.effectList, A.i ) )
        
        set A.i = A.i - 1
        exitwhen A.i < 0
    endloop
    
    call HandleListDestroy( A.effectList )
    
    call PauseTimer( A.t )
    call FlushChildHashtable( H, GetHandleId( A.t ) )
    call DestroyTimer( A.t )
    
    call DestroyGroup( A.g )
    
    set A.g = null
    set A.t = null
    set A.e = null
    set A.caster = null
    call A.l.destroy( )
    call A.destroy( )
endfunction

private function AddHitEffect takes nothing returns nothing
    local integer i = GetRandomInt( 0, 5 )
    
    if i == 0 then
        call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnMissile.mdl", GetEnumUnit( ), "chest" ) )
    elseif i == 1 then
        call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnMissile.mdl", GetEnumUnit( ), "head" ) )
    elseif i == 2 then
        call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnMissile.mdl", GetEnumUnit( ), "left hand" ) )
    elseif i == 3 then
        call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnMissile.mdl", GetEnumUnit( ), "right hand" ) )
    elseif i == 4 then
        call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnMissile.mdl", GetEnumUnit( ), "left foot" ) )
    else
        call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnMissile.mdl", GetEnumUnit( ), "right foot" ) )
    endif
endfunction

private function SpawnEffects takes nothing returns nothing
    local SpellS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local SpellS B = SpellS.create( )
    local real a = GetRandomReal( -bj_PI, bj_PI )
    local integer i
    
    call ForGroup( A.g, function AddHitEffect )
    
    set B.t = CreateTimer( )
    
    set B.i = 0
    set B.l = vector.create( A.l.x + GetRandomReal( A.radius * 0.80, A.radius ) * Cos( a ), A.l.y + GetRandomReal( A.radius * 0.80, A.radius ) * Sin( a ), A.l.z + GetRandomReal( -900.00, 0.00 ) )
    set a = a + bj_PI + GetRandomReal( -bj_PI, bj_PI ) * 0.25
    set B.v = vector.create( A.l.x + GetRandomReal( A.radius * 0.80, A.radius ) * Cos( a ), A.l.y + GetRandomReal( A.radius * 0.80, A.radius ) * Sin( a ), 0.00 )
    set B.v.z = GetAxisZ( B.v.x, B.v.y ) + B.l.z + GetRandomReal( -400.00, 100.00 )
    set B.v.x = B.v.x - B.l.x
    set B.v.y = B.v.y - B.l.y
    set B.v.z = B.v.z - B.l.z
    
    set B.e = AddSpecialEffect( "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl", B.l.x, B.l.y )
    call SetSpecialEffectZ( B.e, B.l.z )
    call SetSpecialEffectOrientation( B.e, Atan2( B.v.y, B.v.x ) * bj_RADTODEG, Atan2( B.v.z, SquareRoot( B.v.x * B.v.x + B.v.y * B.v.y ) ) * bj_RADTODEG, 0.00 )
    call SetSpecialEffectTimeScale( B.e, 2.00 )
    call DestroyEffect( B.e )
    
    set B.e = AddSpecialEffect( "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl", B.l.x, B.l.y )
    call SetSpecialEffectZ( B.e, B.l.z )
    call SetSpecialEffectOrientation( B.e, Atan2( B.v.y, B.v.x ) * bj_RADTODEG, Atan2( B.v.z, SquareRoot( B.v.x * B.v.x + B.v.y * B.v.y ) ) * bj_RADTODEG, 0.00 )
    call SetSpecialEffectAnimation( B.e, "stand" )
    call SetSpecialEffectScale( B.e, 0.50 )
    
    set B.distance = B.v.length( )
    call B.v.normalize( )
    
    set B.speed = B.distance / 0.15 * 0.01
    
    call SaveInteger( H, GetHandleId( B.t ), 0, B )
    call TimerStart( B.t, 0.01, true, function Move )
    
    set A.time = A.time - 0.05
    
    if A.time <= 0.00 then
        call SetUnitFlyHeight( A.caster, 0.00, 0.00 )
        call ShowUnit( A.caster, true )
        call SetUnitAnimation( A.caster, "stand ready" )
        call QueueUnitAnimationByIndex( A.caster, 3 )
        call QueueUnitAnimation( A.caster, "stand" )
        
        set i = 6
    
        loop
            set B = SpellS.create( )
            set B.t = CreateTimer( )
            
            set B.i = 0
            set B.l = vector.create( A.l.x + A.radius * Cos( a ), A.l.y + A.radius * Sin( a ), A.l.z )
            set B.v = vector.create( A.l.x, A.l.y, 0.00 )
            set B.v.z = GetAxisZ( B.v.x, B.v.y ) + 100.00
            set B.v.x = B.v.x - B.l.x
            set B.v.y = B.v.y - B.l.y
            set B.v.z = B.v.z - B.l.z
            
            set B.e = AddSpecialEffect( "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl", B.l.x, B.l.y )
            call SetSpecialEffectZ( B.e, B.l.z )
            call SetSpecialEffectOrientation( B.e, Atan2( B.v.y, B.v.x ) * bj_RADTODEG, Atan2( B.v.z, SquareRoot( B.v.x * B.v.x + B.v.y * B.v.y ) ) * bj_RADTODEG, 0.00 )
            call SetSpecialEffectTimeScale( B.e, 2.00 )
            call DestroyEffect( B.e )
            
            set B.e = AddSpecialEffect( "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl", B.l.x, B.l.y )
            call SetSpecialEffectZ( B.e, B.l.z )
            call SetSpecialEffectOrientation( B.e, Atan2( B.v.y, B.v.x ) * bj_RADTODEG, Atan2( B.v.z, SquareRoot( B.v.x * B.v.x + B.v.y * B.v.y ) ) * bj_RADTODEG, 0.00 )
            call SetSpecialEffectAnimation( B.e, "stand" )
            call SetSpecialEffectScale( B.e, 0.50 )
            
            set B.distance = B.v.length( )
            call B.v.normalize( )
            
            set B.speed = B.distance / 0.20 * 0.01
            
            call SaveInteger( H, GetHandleId( B.t ), 0, B )
            call TimerStart( B.t, 0.01, true, function Move )
            
            set i = i - 1
            exitwhen i <= 0
            set a = a - bj_PI / 6.00 * 2.00
        endloop
        
        call DestroyEffect( A.e )
        
        set A.e = AddSpecialEffect( "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl", A.l.x, A.l.y )
        call SetSpecialEffectYaw( A.e, GetUnitFacing( A.caster ) )
        call DestroyEffect( A.e )
        
        set A.e = AddSpecialEffectTarget( "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl", A.caster, "weapon" )
        
        if GetLocalPlayer( ) == A.p then
            call ClearSelection( )
            call SelectUnit( A.caster, true )
        endif
        
        call TimerStart( A.t, 2.10, false, function Damage )
    endif
endfunction

private function JumpClones takes nothing returns nothing
    local SpellS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local SpellS B
    local integer i = 6
    local real a = -bj_PI
    local unit u
    
    call GroupEnumUnitsInRange( TempGroup, A.l.x, A.l.y, A.radius, null )
    
    loop
        set u = FirstOfGroup( TempGroup )
        exitwhen u == null
        call GroupRemoveUnit( TempGroup, u )
        
        if IsUnitInRangeXY( u, A.l.x, A.l.y, A.radius + UNIT_MAX_COLLISION ) then
            if UnitAlive( u ) and IsUnitEnemy( u, A.p ) then
                call GroupAddUnit( A.g, u )
                call SetUnitStunned( u, true )
                call SetUnitTimeScale( u, 0.00 )
            endif
        endif
    endloop
    
    call PauseUnit( A.caster, true )
    call ShowUnit( A.caster, false )
    
    set A.l.z = GetAxisZ( A.l.x, A.l.y ) + GetUnitFlyHeight( A.caster )
    
    set A.e = AddSpecialEffect( "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl", A.l.x, A.l.y )
    call SetSpecialEffectZ( A.e, A.l.z )
    call SetSpecialEffectYaw( A.e, GetUnitFacing( A.caster ) )
    call DestroyEffect( A.e )
    
    set A.e = AddSpecialEffect( "Abilities\\Spells\\Orc\\Bloodlust\\BloodlustTarget.mdl", A.l.x, A.l.y )
    call SetSpecialEffectZ( A.e, A.l.z / 2.00 )
    call SetSpecialEffectTimeScale( A.e, 0.10 )
    call SetSpecialEffectScale( A.e, 50.00 )
    call SetSpecialEffectAlpha( A.e, 175 )
    
    loop
        set B = SpellS.create( )
        
        set B.t = CreateTimer( )
        
        set B.l = vector.create( A.l.x, A.l.y, A.l.z )
        set B.v = vector.create( Cos( a ), Sin( a ), Cos( bj_PI * 0.50 ) )
        
        set B.i = 1
        set B.speed = 40.00
        set B.distance = A.radius
        
        set B.e = AddSpecialEffect( "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageMissile.mdl", B.l.x, B.l.y )
        call SetSpecialEffectZ( B.e, B.l.z )
        call SetSpecialEffectOrientation( B.e, a * bj_RADTODEG, 45.00, 0.00 )
        
        call SaveInteger( H, GetHandleId( B.t ), 0, B )
        call TimerStart( B.t, 0.01, true, function Move )
        
        set i = i - 1
        exitwhen i <= 0
        set a = a - bj_PI / 5.00
    endloop
    
    set A.radius = A.radius * 1.50
    set A.time = 2.00
    call TimerStart( A.t, 0.05, true, function SpawnEffects )
endfunction

private function Jump takes nothing returns nothing
    local SpellS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    
    if UnitAddAbility( A.caster, 'Arav' ) then
        call UnitRemoveAbility( A.caster, 'Arav' )
    endif
    
    call SetUnitFlyHeight( A.caster, 800.00, 800.00 / 0.20 )
    
    call DestroyEffect( A.e )
    
    set A.e = AddSpecialEffect( "Units\\NightElf\\Wisp\\WispExplode.mdl", A.l.x, A.l.y )
    call SetSpecialEffectAnimationOffsetPercent( A.e, 0.20 )
    call SetSpecialEffectTimeScale( A.e, 3.00 )
    call DestroyEffect( A.e )
    
    call TimerStart( A.t, 0.20, false, function JumpClones )
endfunction

private function Spell_Actions takes nothing returns nothing
    local SpellS A = SpellS.create( )
    local integer i
    local real a = GetRandomReal( -bj_PI, bj_PI )
    
    set A.t = CreateTimer( )
    set A.caster = GetTriggerUnit( )
    set A.p = GetOwningPlayer( A.caster )
    set A.l = vector.create( GetUnitX( A.caster ), GetUnitY( A.caster ), 0.00 )
    set A.g = CreateGroup( )
    set A.e = AddSpecialEffect( "Abilities\\Spells\\Undead\\DarkRitual\\DarkRitualTarget.mdl", A.l.x, A.l.y )
    call SetSpecialEffectScale( A.e, 2.00 )
    
    set A.damage = 200.00 // урон
    set A.radius = 600.00 // радиус
    set A.attackType = ATTACK_TYPE_CHAOS // тип атаки
    set A.damageType = DAMAGE_TYPE_SONIC // тип урона
    set A.weaponType = null
    
    set A.effectList = HandleListCreate( )
    
    set A.i = 60 // количество эффектов отображения радиуса
    set i = A.i
    
    loop
        set bj_lastCreatedEffect = AddSpecialEffect( "Abilities\\Spells\\Orc\\Bloodlust\\BloodlustTarget.mdl", A.l.x + A.radius * Cos( a ), A.l.y + A.radius * Sin( a ) )
        call SetSpecialEffectZ( bj_lastCreatedEffect, GetSpecialEffectZ( bj_lastCreatedEffect ) + 50.00 )
        call HandleListAddHandle( A.effectList, bj_lastCreatedEffect )
        
        set i = i - 1
        exitwhen i <= 0
        set a = a + bj_PI / A.i * 2.00
    endloop
    
    call SaveInteger( H, GetHandleId( A.t ), 0, A )
    call TimerStart( A.t, 1.50, false, function Jump )
endfunction

//===========================================================================
private function Spell_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function InitTrig_Spell takes nothing returns nothing
    set gg_trg_Spell = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Spell, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Spell, Condition( function Spell_Conditions ) )
    call TriggerAddAction( gg_trg_Spell, function Spell_Actions )
endfunction
endlibrary

Загруженные файлы
28

» WarCraft 3 / Заклинания на заказ

LastUchiha, напиши просто, что через 5 секунд после получения последнего стака - все стаки должны сброситься, так будет понятнее, перенеси строку call TimerStart( t, 5.00, false, function RemoveDebuff ) рядом к строке call SaveInteger( udg_H, i, 1, stack )
должно выйти так
        if stack < udg_BDMax then
            call SaveInteger( udg_H, i, 1, stack )
        	call TimerStart( t, 5.00, false, function RemoveDebuff )
        else
            call IssueTargetOrder( udg_TempUnit, "soulburn", damaged )
        endif
время таймера будет обновляться каждый раз, когда юнит получает автоатаку, за исключением наличия последнего стака
28

» WarCraft 3 / Заклинания на заказ

Вышла новая версия! Прокрутить к ресурсу
LastUchiha, я сначала подумал, что может в цикле накосячил из-за недосыпа, но нет, это сайленс прикалывается. Когда обнулял значения сайленса, поставил периодичность урона на 0.00, в итоге, оно, похоже, каждые 0.00 секунд дамажило с 0 урона, вызывая триггер получения урона, решилось просто - выставил периодичность урона на 99999999999999, ну и приколы..

вот обновлённая карта с исправлением предыдущего косяка
28

» WarCraft 3 / Заклинания на заказ

Desgul, светлая магия и отражение энергии это снаряд, молния или мгновенное?
28

» WarCraft 3 / Анимация юнита при нажатии способности

Если эффект абилки триггерный, то в качестве завершения используй end cast. Остальные настройки есть у канала, follow through time на 3 секунды поставь
28

» WarCraft 3 / Заклинания на заказ

LastUchiha, ахахаха, блин, извиняюсь, перед сном делал спелл, вытащи из лупа в первом триггере всё, кроме добавления события, поставь чуть ниже/выше пика юнитов, а то там хэштаблица создаётся на каждого выбранного юнита
28

» WarCraft 3 / Заклинания на заказ

LastUchiha, стаки на 63 строке триггера EventDamage, но я пихнул туда udg_BDMax, поскольку подходило под тз, лучше просто указать макс кол-во стаков
28

» WarCraft 3 / Заклинания на заказ

LastUchiha, если ты захочешь отнимать больше защиты или добавить больше стаков, что превысит 123 единицы (1+2+4+8+16+32+64), то добавь просто новые значения в бд (х2 предыдущего числа, т.е. 128/256/512/1024...), и не забудь указать новое количество индексов для BDMax
28

» WarCraft 3 / Заклинания на заказ

Выполнение заказа

Заклинание готово!

Понижение защиты

инструкция по импорту
скопировать папку Initialization и вставить в свою карту, перекопировать редактор объектов и вставить в свою карту, в триггере Melee Initialization настроить бд в соответствии с редактором объектов
в триггере EventDamage на 81 строке указать даммика, что будет кастовать таргетный сайленс
на 70 строке можно изменить время спадения дебаффа на броню
на 61 строке можешь настроить формулу уменьшения брони
на 54 строке аура торнадо для отображения дебаффа на юните + статус бар (на 24-25 то же самое)
советую сделать прелоад ауры, чтобы при первом получении не происходил пролаг

Код

EventDamage
function SetBonusArmorNegative takes unit u, integer value returns nothing
    local integer i = udg_BDMax
    
    loop
        exitwhen i <= 0
        
        if udg_BDValue[i] <= value then
            call UnitAddAbility( u, udg_BDAbil[i] )
        
            set value = value - udg_BDValue[i]
        else
            call UnitRemoveAbility( u, udg_BDAbil[i] )
        endif
        
        set i = i - 1
    endloop
endfunction

function RemoveDebuff takes nothing returns nothing
    local timer t = GetExpiredTimer( )
    local integer i = GetHandleId( t )
    local unit u = LoadUnitHandle( udg_H, i, 0 )
    
    call UnitRemoveAbility( u, 'A009' )
    call UnitRemoveAbility( u, 'B000' )
    call SetBonusArmorNegative( u, 0 )
        
    call RemoveSavedInteger( udg_H, GetHandleId( u ), 0 )
    
    call FlushChildHashtable( udg_H, i )
    call DestroyTimer( t )
    
    set u = null
    set t = null
endfunction

function Trig_EventDamage_Actions takes nothing returns nothing
    local unit damaged
    local timer t
    local integer i
    local integer stack
    
    if GetUnitAbilityLevel( GetTriggerUnit( ), 'Bspo' ) > 0 then
        set damaged = GetTriggerUnit( )
        call UnitRemoveAbility( damaged, 'Bspo' )
        
        set t = LoadTimerHandle( udg_H, GetHandleId( damaged ), 0 )
        
        if t == null then
            set t = CreateTimer( )
            
            call SaveTimerHandle( udg_H, GetHandleId( damaged ), 0, t )
            call UnitAddAbility( damaged, 'A009' )
            call SaveUnitHandle( udg_H, GetHandleId( t ), 0, damaged )
        endif
        
        set i = GetHandleId( t )
        set stack = LoadInteger( udg_H, i, 1 ) + 1
        
        call SetUnitAbilityLevel( damaged, 'A009', stack )
        call SetBonusArmorNegative( damaged, IMaxBJ( 1, R2I( GetHeroLevel( GetEventDamageSource( ) ) * 0.10 ) ) * stack )
        
        if stack < udg_BDMax then
            call SaveInteger( udg_H, i, 1, stack )
        else
            call IssueTargetOrder( udg_TempUnit, "soulburn", damaged )
        endif
        
        call TimerStart( t, 5.00, false, function RemoveDebuff )
        
        set t = null
        set damaged = null
    endif
endfunction

//===========================================================================
function InitTrig_EventDamage takes nothing returns nothing
    set gg_trg_EventDamage = CreateTrigger(  )
    call TriggerAddAction( gg_trg_EventDamage, function Trig_EventDamage_Actions )
    set udg_TempUnit = CreateUnit( Player( PLAYER_NEUTRAL_PASSIVE ), 'u000', 0.00, 0.00, 0.00 )
endfunction
28

» WarCraft 3 / Заклинания на заказ

UndeadFisher, на стандартных эффектах это будет менее эффектно выглядеть, но попробую что-нибудь придумать
28

» WarCraft 3 / Заклинания на заказ

Выполнение заказа

Заклинание готово!

инструкция по импорту
скопировать папку Initialization и вставить в свою карту, перекопировать нестандартное ро и вставить в свою карту
в триггере Spell настроить всё, что помечено комментарием, на своё усмотрение, остальное требует минимальных знаний джасса
выполнено на UjAPI

Код

AllGlobals
library AllGlobalsLib
globals
    constant hashtable H = InitHashtable( )
    constant real UNIT_MAX_COLLISION = 200.00
    
    real MaxX
    real MinX
    real MaxY
    real MinY
endglobals

native UnitAlive takes unit id returns boolean

struct vector
    real x
    real y
    real z
    
    method length takes nothing returns real
        return SquareRoot( x * x + y * y + z * z )
    endmethod
    
    method normalize takes nothing returns nothing
        local real l = length( )
        
        if l == 0.00 then
            set l = 1.00
        endif
        
        set x = x / l
        set y = y / l
        set z = z / l
    endmethod
    
    static method create takes real x, real y, real z returns thistype
        local thistype this = thistype.allocate( )
        
        set this.x = x
        set this.y = y
        set this.z = z
        
        return this
    endmethod
endstruct

function RemoveStun takes nothing returns nothing
    local timer t = GetExpiredTimer( )
    local integer i = GetHandleId( t )
    
    call SetUnitStunned( LoadUnitHandle( H, i, 0 ), false )
    call DestroyEffect( LoadEffectHandle( H, i, 1 ) )
    
    call FlushChildHashtable( H, i )
    call DestroyTimer( t )
    
    set t = null
endfunction

function StunUnit takes unit u, real time, effect e returns nothing
    local timer t = CreateTimer( )
    
    call SetUnitStunned( u, true )
    
    call SaveUnitHandle( H, GetHandleId( t ), 0, u )
    call SaveEffectHandle( H, GetHandleId( t ), 1, e )
    call TimerStart( t, time, false, function RemoveStun )
    
    set t = null
endfunction

//===========================================================================
function InitTrig_AllGlobals takes nothing returns nothing
    //set gg_trg_AllGlobals = CreateTrigger(  )
    local rect r = GetWorldBounds( )
    
    set MaxX = GetRectMaxX( r )
    set MinX = GetRectMinX( r )
    set MaxY = GetRectMaxY( r )
    set MinY = GetRectMinY( r )
    
    call RemoveRect( r )
    set r = null
endfunction
endlibrary

Spell
library SpellLib
globals
    private constant group TempGroup = CreateGroup( )
    private item TempItem = null
endglobals

private struct ProjectileS
    timer t
    effect e
    effect e1
    
    real a
    
    vector array v[4]
    vector last
    
    real time
    real timeMax
endstruct

private struct SpellS
    timer t
    unit caster
    unit target
    player p
    vector v
    group g
    integer b
    integer lvl
    
    effect e
    effect e1
    
    real radius
    real damage
    real speed
    real distance
    real time
    
    attacktype attackType
    damagetype damageType
    weapontype weaponType
endstruct

private function Move takes nothing returns nothing
    local SpellS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local SpellS B
    local real x = GetUnitX( A.target )
    local real y = GetUnitY( A.target )
    local real x1
    local real y1
    local unit u
    
    if A.b == 1 then
        set A.b = 2
        
        set bj_lastCreatedEffect = AddSpecialEffect( "Abilities\\Weapons\\DemolisherFireMissile\\DemolisherFireMissile.mdl", x, y )
        call SetSpecialEffectZ( bj_lastCreatedEffect, GetSpecialEffectZ( bj_lastCreatedEffect ) + 50.00 )
        call SetSpecialEffectOrientation( bj_lastCreatedEffect, Atan2( A.v.y, A.v.x ) * bj_RADTODEG, -90.00, 0.00 )
        call DestroyEffect( bj_lastCreatedEffect )
        
        set bj_lastCreatedEffect = AddSpecialEffect( "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl", x, y )
        call SetSpecialEffectZ( bj_lastCreatedEffect, GetSpecialEffectZ( bj_lastCreatedEffect ) + 50.00 )
        call SetSpecialEffectOrientation( bj_lastCreatedEffect, Atan2( A.v.y, A.v.x ) * bj_RADTODEG, -90.00, 0.00 )
        call DestroyEffect( bj_lastCreatedEffect )
        
        set bj_lastCreatedEffect = AddSpecialEffect( "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl", x, y )
        call SetSpecialEffectZ( bj_lastCreatedEffect, GetSpecialEffectZ( bj_lastCreatedEffect ) + 50.00 )
        call SetSpecialEffectOrientation( bj_lastCreatedEffect, Atan2( A.v.y, A.v.x ) * bj_RADTODEG, -90.00, 0.00 )
        call DestroyEffect( bj_lastCreatedEffect )
        
        call UnitDamageTarget( A.caster, A.target, A.damage, false, false, A.attackType, A.damageType, A.weaponType )
        
        call DestroyEffect( A.e )
        call DestroyEffect( A.e1 )
        
        set A.e = AddSpecialEffectTarget( "Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeEmbers.mdl", A.target, "origin" )
        set A.e1 = AddSpecialEffectTarget( "Abilities\\Spells\\Other\\BreathOfFire\\BreathOfFireDamage.mdl", A.target, "origin" )
    endif
    
    if A.speed > A.distance then
        set A.speed = A.distance
    endif
    
    set x = x + A.speed * A.v.x
    set y = y + A.speed * A.v.y
    
    if A.b >= 2 then
        set A.b = A.b + 1
        
        if A.b == 6 then
            set bj_lastCreatedEffect = AddSpecialEffect( "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile_mini.mdl", x, y )
            call SetSpecialEffectZ( bj_lastCreatedEffect, GetSpecialEffectZ( bj_lastCreatedEffect ) + 30.00 )
            call DestroyEffect( bj_lastCreatedEffect )
            
            set A.b = 2
        endif
    endif
    
    set A.distance = A.distance - A.speed
    
    call SetItemPosition( TempItem, x, y )
    call SetItemVisible( TempItem, false )
    
    set x1 = GetItemX( TempItem )
    set y1 = GetItemY( TempItem )
    
    if ( x - 1.00 > x1 or x + 1.00 < x1 ) or ( y - 1.00 > y1 or y + 1.00 < y1 ) then
        set A.distance = 0.00
        call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Other\\Volcano\\VolcanoDeath.mdl", x, y ) )
    else
        call SetUnitX( A.target, x )
        call SetUnitY( A.target, y )
    endif
    
    if A.g != null then
        call GroupEnumUnitsInRange( TempGroup, x, y, A.radius + UNIT_MAX_COLLISION, null )
        
        loop
            set u = FirstOfGroup( TempGroup )
            exitwhen u == null
            call GroupRemoveUnit( TempGroup, u )
            
            if not IsUnitInGroup( u, A.g ) and IsUnitInRange( u, A.target, A.radius ) then
                if UnitAlive( u ) and IsUnitEnemy( u, A.p ) then
                    call GroupAddUnit( A.g, u )
                    
                    call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Weapons\\LordofFlameMissile\\LordofFlameMissile.mdl", u, "chest" ) )
                    call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Items\\AIfb\\AIfbSpecialArt.mdl", u, "chest" ) )
                    
                    call UnitDamageTarget( A.caster, A.target, A.damage, false, false, A.attackType, A.damageType, A.weaponType )
                    call UnitDamageTarget( A.caster, u, A.damage, false, false, A.attackType, A.damageType, A.weaponType )
                    call StunUnit( u, 1.00, AddSpecialEffectTarget( "Abilities\\Spells\\Human\\Thunderclap\\ThunderclapTarget.mdl", u, "overhead" ) )
                    
                    set B = SpellS.create( )
                    
                    set B.t = CreateTimer( )
                    set B.target = u
                    set B.v = vector.create( GetUnitX( u ) - x, GetUnitY( u ) - y, 0.00 )
                    call B.v.normalize( )
                    set B.b = 0
                    
                    call SetUnitStunned( u, true )
                    
                    set A.speed = A.speed * 0.90
                    set B.speed = A.speed
                    set B.distance = B.speed / 0.015 * 0.50
                    set A.distance = A.distance * 0.90
                    
                    call SaveInteger( H, GetHandleId( B.t ), 0, B )
                    call TimerStart( B.t, 0.01, false, function Move )
                endif
            endif
        endloop
    endif
    
    if A.distance <= 0.00 or not UnitAlive( A.target ) then
        call PauseTimer( A.t )
        call FlushChildHashtable( H, GetHandleId( A.t ) )
        call DestroyTimer( A.t )
        
        if A.b >= 2 then
            call DestroyEffect( A.e )
            call DestroyEffect( A.e1 )
            set A.e = null
            set A.e1 = null
            
            if UnitAlive( A.target ) then
                call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl", A.target, "chest" ) )
                call StunUnit( A.target, 1.00 + 1.00 * A.lvl, AddSpecialEffectTarget( "Abilities\\Spells\\Human\\Thunderclap\\ThunderclapTarget.mdl", A.target, "overhead" ) )
            endif
        endif
        
        call SetUnitStunned( A.target, false )
        
        call DestroyGroup( A.g )
        
        set A.t = null
        set A.g = null
        set A.caster = null
        set A.target = null
        call A.v.destroy( )
        call A.destroy( )
    else
        call TimerStart( A.t, 0.01, false, function Move )
    endif
endfunction

private function MoveProjectile takes nothing returns nothing
    local ProjectileS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local real array x
    local real array y
    local real array z
    local integer k = 0
    local integer i
    
    set A.time = A.time + 0.01 / A.timeMax
    
    if A.time >= 0.50 then
        set A.time = A.time + 0.01 / A.timeMax
    endif
    
    if A.time > 1.00 then
        set A.time = 1.00
    endif
    
    loop
        set x[k] = A.v[k].x
        set y[k] = A.v[k].y
        set z[k] = A.v[k].z
        
        set k = k + 1
        exitwhen k >= 4
    endloop
    
    set k = 0
    
    loop
        set i = 0
        
        loop
            set x[i] = ( 1.00 - A.time ) * x[i] + A.time * x[i + 1]
            set y[i] = ( 1.00 - A.time ) * y[i] + A.time * y[i + 1]
            set z[i] = ( 1.00 - A.time ) * z[i] + A.time * z[i + 1]
            
            set i = i + 1
            exitwhen i > 4 - k
        endloop
        
        set k = k + 1
        exitwhen k >= 4 - 1
    endloop
    
    call SetSpecialEffectPositionWithZ( A.e, x[0], y[0], z[0] )
    call SetSpecialEffectPositionWithZ( A.e1, x[0], y[0], z[0] )
    call SetSpecialEffectOrientation( A.e, A.a, Atan2( z[0] - A.last.z, SquareRoot( ( x[0] - A.last.x ) * ( x[0] - A.last.x ) + ( y[0] - A.last.y ) * ( y[0] - A.last.y ) ) ) * bj_RADTODEG, 0.00 )
    call SetSpecialEffectOrientation( A.e1, A.a, Atan2( z[0] - A.last.z, SquareRoot( ( x[0] - A.last.x ) * ( x[0] - A.last.x ) + ( y[0] - A.last.y ) * ( y[0] - A.last.y ) ) ) * bj_RADTODEG, 0.00 )
    
    if A.time >= 1.00 then
        call PauseTimer( A.t )
        call FlushChildHashtable( H, GetHandleId( A.t ) )
        call DestroyTimer( A.t )
        
        call DestroyEffect( A.e )
        call DestroyEffect( A.e1 )
        
        set i = 0
        
        loop
            call A.v[i].destroy( )
            
            set i = i + 1
            exitwhen i >= 4
        endloop
        
        set A.e = null
        set A.e1 = null
        call A.last.destroy( )
        call A.destroy( )
    else
        set A.last.x = x[0]
        set A.last.y = y[0]
        set A.last.z = z[0]
    endif
endfunction

private function Spell_Actions takes nothing returns nothing
    local SpellS A = SpellS.create( )
    local ProjectileS B
    local real x
    local real y
    local real z
    local real a
    local real d
    
    set A.t = CreateTimer( )
    set A.caster = GetTriggerUnit( )
    set A.target = GetSpellTargetUnit( )
    set A.p = GetOwningPlayer( A.caster )
    set A.g = CreateGroup( )
    set A.b = 1
    set A.radius = 64.00 // радиус столкновения
    
    set A.e = AddSpecialEffectTarget( "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnMissile.mdl", A.caster, "left hand" )
    set A.e1 = AddSpecialEffectTarget( "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnMissile.mdl", A.caster, "right hand" )
    
    set x = GetUnitX( A.caster )
    set y = GetUnitY( A.caster )
    set z = GetAxisZ( x, y ) + GetUnitFlyHeight( A.caster ) + 50.00
    
    set A.v = vector.create( GetUnitX( A.target ) - x, GetUnitY( A.target ) - y, 0.00 )
    set d = A.v.length( )
    call A.v.normalize( )
    set a = Atan2( A.v.y, A.v.x )
    
    set A.lvl = GetUnitAbilityLevel( A.caster, GetSpellAbilityId( ) )
    
    set A.distance = 600.00 + 100.00 * A.lvl // дистанция
    set A.speed = A.distance * 0.015 // скорость
    set A.damage = 25.00 + 10.00 * A.lvl // урон
    
    set A.attackType = ATTACK_TYPE_MAGIC // тип атаки
    set A.damageType = DAMAGE_TYPE_FIRE // тип урона
    set A.weaponType = null // тип оружия (звук)
    
    call SetUnitStunned( A.target, true )
    call GroupAddUnit( A.g, A.caster )
    call GroupAddUnit( A.g, A.target )
    
    call SaveInteger( H, GetHandleId( A.t ), 0, A )
    call TimerStart( A.t, 1.10, false, function Move )
    
    //===
    set B = ProjectileS.create( )
    set B.t = CreateTimer( )
    
    set B.a = a + bj_PI * 0.20
    
    set B.last = vector.create( x, y, z )
    set B.v[0] = vector.create( B.last.x, B.last.y, B.last.z )
    set B.v[1] = vector.create( B.v[0].x - ( d / 2.00 + 500.00 ) * Cos( B.a ), B.v[0].y - ( d / 2.00 + 500.00 ) * Sin( B.a ), B.v[0].z + 300.00 )
    set B.v[2] = vector.create( B.v[0].x + ( d - 200.00 ) * Cos( B.a + bj_PI * 0.10 ), B.v[0].y + ( d - 200.00 ) * Sin( B.a + bj_PI * 0.10 ), B.v[0].z )
    set B.v[3] = vector.create( GetUnitX( A.target ), GetUnitY( A.target ), 0.00 )
    set B.v[3].z = GetAxisZ( B.v[3].x, B.v[3].y ) + 50.00
    
    set B.e = AddSpecialEffect( "units\\human\\phoenix\\phoenix.mdl", B.v[0].x, B.v[0].y )
    call SetSpecialEffectZ( B.e, B.v[0].z )
    call SetSpecialEffectScale( B.e, 0.60 )
    call SetSpecialEffectAlpha( B.e, 155 )
    
    set B.e1 = AddSpecialEffect( "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl", B.v[0].x, B.v[0].y )
     
    set B.a = B.a * bj_RADTODEG
    set B.time = 0.00
    set B.timeMax = 1.50
    
    call SaveInteger( H, GetHandleId( B.t ), 0, B )
    call TimerStart( B.t, 0.01, true, function MoveProjectile )
    
    //===
    set B = ProjectileS.create( )
    set B.t = CreateTimer( )
    
    set B.a = a - bj_PI * 0.20
    
    set B.last = vector.create( x, y, z )
    set B.v[0] = vector.create( B.last.x, B.last.y, B.last.z )
    set B.v[1] = vector.create( B.v[0].x - ( d / 2.00 + 500.00 ) * Cos( B.a ), B.v[0].y - ( d / 2.00 + 500.00 ) * Sin( B.a ), B.v[0].z + 300.00 )
    set B.v[2] = vector.create( B.v[0].x + ( d - 200.00 ) * Cos( B.a - bj_PI * 0.10 ), B.v[0].y + ( d - 200.00 ) * Sin( B.a - bj_PI * 0.10 ), B.v[0].z )
    set B.v[3] = vector.create( GetUnitX( A.target ), GetUnitY( A.target ), 0.00 )
    set B.v[3].z = GetAxisZ( B.v[3].x, B.v[3].y ) + 50.00
    
    set B.e = AddSpecialEffect( "units\\human\\phoenix\\phoenix.mdl", B.v[0].x, B.v[0].y )
    call SetSpecialEffectZ( B.e, B.v[0].z )
    call SetSpecialEffectScale( B.e, 0.60 )
    call SetSpecialEffectAlpha( B.e, 155 )
    
    set B.e1 = AddSpecialEffect( "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl", B.v[0].x, B.v[0].y )
    
    set B.a = B.a * bj_RADTODEG
    set B.time = 0.00
    set B.timeMax = 1.50
    
    call SaveInteger( H, GetHandleId( B.t ), 0, B )
    call TimerStart( B.t, 0.01, true, function MoveProjectile )
endfunction

//===========================================================================
private function Spell_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000' // равкод
endfunction

function InitTrig_Spell takes nothing returns nothing
    set gg_trg_Spell = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Spell, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Spell, Condition( function Spell_Conditions ) )
    call TriggerAddAction( gg_trg_Spell, function Spell_Actions )
    
    set TempItem = CreateItem( 'spsh', 0.00, 0.00 )
    call SetItemVisible( TempItem, false )
endfunction
endlibrary

Загруженные файлы