Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
vJass
Тип:
Способность
Версия Warcraft:
1.26+

Опалесценция

(защитная)

Герой временно растворяется в окружающей среде в виде пучков света, становясь недосягаемым.
код
library OpalescenceLib
globals
    private constant hashtable PascalTriangle = InitHashtable( )
    private constant hashtable H = InitHashtable( )
    private constant location LFZ = Location( 0.00, 0.00 )
    private constant group TempGroup = CreateGroup( )
    private constant integer FaerieID    = 'u000'
    private constant integer NEDeathID   = 'u001'
    private constant integer WispID      = 'u002'
    private constant integer PhaseID     = 'u003'
    private constant integer BlinkID     = 'u004'
    private constant integer PolymorphID = 'u005'
    private integer PascalTriangleRows = 2
    private unit TempUnit = null
    private real MaxX
    private real MinX
    private real MaxY
    private real MinY
endglobals

private function GetLocZ takes real x, real y returns real
    call MoveLocation( LFZ, x, y )
    return GetLocationZ( LFZ )
endfunction

private function SetUnitPositionEx takes unit u, real x, real y returns nothing
    if x > MaxX then
        set x = MaxX
    elseif x < MinX then
        set x = MinX
    endif
    
    if y > MaxY then
        set y = MaxY
    elseif y < MinY then
        set y = MinY
    endif
    
    call SetUnitX( u, x )
    call SetUnitY( u, y )
endfunction

private function RegistPascalTriangle takes integer i returns nothing
    local integer n
    local integer k
    
    if i > PascalTriangleRows then
        set n = PascalTriangleRows
        
        loop
            set k = 0
            
            loop
                call SaveInteger( PascalTriangle, n, k, LoadInteger( PascalTriangle, n - 1, k - 1 ) + LoadInteger( PascalTriangle, n - 1, k ) )
                
                set k = k + 1
                exitwhen k > n
            endloop
            
            set n = n + 1
            exitwhen n > i
        endloop
    
        set PascalTriangleRows = i
    endif
endfunction

private struct Point
    real x
    real y
    real z
    
    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

private struct Bezier
    unit dummy
    real time
    real timeMax
    integer pCount
    
    Point array p[10]
    Point last
endstruct

private struct OpalescenceS
    unit caster
    player p
    boolexpr b
    
    real x
    real y
    real damage
    real radius
    real time
endstruct

private function OpalescenceMove takes nothing returns nothing
    local Bezier A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local real x = 0.00
    local real y = 0.00
    local real z = 0.00
    local real r
    local integer i = 0
    
    set A.time = A.time + ( 0.03125 / A.timeMax )
    
    if A.time > 1.00 then
        set A.time = 1.00
    endif
    
    loop
        set r = LoadInteger( PascalTriangle, A.pCount, i ) * Pow( 1.00 - A.time, A.pCount - i ) * Pow( A.time, i )
        set x = x + r * A.p[i].x
        set y = y + r * A.p[i].y
        set z = z + r * A.p[i].z
        
        set i = i + 1
        exitwhen i > A.pCount
    endloop
    
    call SetUnitPositionEx( A.dummy, x, y )
    call SetUnitFlyHeight( A.dummy, z - GetLocZ( x, y ), 0.00 )
    call SetUnitFacing( A.dummy, Atan2( y - A.last.y, x - A.last.x ) * bj_RADTODEG )
    
    if A.time >= 1.00 then
        call PauseTimer( GetExpiredTimer( ) )
        call FlushChildHashtable( H, GetHandleId( GetExpiredTimer( ) ) )
        call DestroyTimer( GetExpiredTimer( ) )
        
        loop
            call A.p[A.pCount].destroy( )
            
            set A.pCount = A.pCount - 1
            exitwhen A.pCount < 0
        endloop
        
        call A.last.destroy( )
        
        call SetUnitAnimation( A.dummy, "death" )
        call UnitApplyTimedLife( A.dummy, 'BTLF', 2.00 )
        
        set A.dummy = null
        call A.destroy( )
    else
        set A.last.x = x
        set A.last.y = y
        set A.last.z = z
    endif
endfunction

private function OpalescenceDamage takes nothing returns nothing
    local OpalescenceS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
    local unit u
    
    set A.time = A.time - 0.01
    
    if A.time == 0.20 then
        set TempUnit = CreateUnit( A.p, WispID, A.x, A.y, GetRandomReal( 0.00, 360.00 ) )
        call SetUnitX( TempUnit, A.x )
        call SetUnitY( TempUnit, A.y )
        call SetUnitTimeScale( TempUnit, 1.50 )
        call UnitApplyTimedLife( TempUnit, 'BTLF', 2.00 )
    endif
    
    if A.time <= 0.00 then
        call PauseTimer( GetExpiredTimer( ) )
        call FlushChildHashtable( H, GetHandleId( GetExpiredTimer( ) ) )
        call DestroyTimer( GetExpiredTimer( ) )
    
        set udg_TempUnit = A.caster
        call GroupEnumUnitsInRange( TempGroup, A.x, A.y, A.radius + 200.00, A.b )
    
        loop
            set u = FirstOfGroup( TempGroup )
            exitwhen u == null
            call GroupRemoveUnit( TempGroup, u )
            
            if IsUnitInRangeXY( u, A.x, A.y, A.radius ) then
                call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdl", u, "chest" ) )
                
                if A.damage >= 0.00 then
                    call UnitDamageTarget( A.caster, u, A.damage, false, false, null, null, null )
                else
                    call SetWidgetLife( u, GetWidgetLife( u ) - A.damage )
                endif
            endif
        endloop
    
        set TempUnit = CreateUnit( A.p, BlinkID, A.x, A.y, GetRandomReal( 0.00, 360.00 ) )
        call SetUnitX( TempUnit, A.x )
        call SetUnitY( TempUnit, A.y )
        call SetUnitScale( TempUnit, 2.00, 2.00, 2.00 )
        call SetUnitAnimation( TempUnit, "birth" )
        call UnitApplyTimedLife( TempUnit, 'BTLF', 1.00 )
    
        set TempUnit = CreateUnit( A.p, PhaseID, A.x, A.y, GetRandomReal( 0.00, 360.00 ) )
        call SetUnitX( TempUnit, A.x )
        call SetUnitY( TempUnit, A.y )
        call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
        call SetUnitAnimation( TempUnit, "birth" )
        call UnitApplyTimedLife( TempUnit, 'BTLF', 1.00 )
    
        set TempUnit = CreateUnit( A.p, NEDeathID, A.x, A.y, GetRandomReal( 0.00, 360.00 ) )
        call SetUnitX( TempUnit, A.x )
        call SetUnitY( TempUnit, A.y )
        call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
        
        call SetUnitX( A.caster, A.x )
        call SetUnitY( A.caster, A.y )
        
        call ShowUnit( A.caster, true )
        call SetUnitInvulnerable( A.caster, false )
        
        if GetLocalPlayer( ) == A.p then
            call ClearSelection( )
            call SelectUnit( A.caster, true )
        endif
        
        set A.caster = null
        call A.destroy( )
    endif
endfunction

private function SetScale takes nothing returns nothing
    local timer t = GetExpiredTimer( )
    local integer i = GetHandleId( t )
    local real r = LoadReal( H, i, 1 ) + 0.10
    
    if r >= 30.00 then
        call KillUnit( LoadUnitHandle( H, i, 0 ) )
        
        call PauseTimer( t )
        call DestroyTimer( t )
        call FlushChildHashtable( H, i )
    else
        call SetUnitScale( LoadUnitHandle( H, i, 0 ), r, r, r )
        call SaveReal( H, i, 1, r )
    endif
    
    set t = null
endfunction

function Opalescence_Actions takes unit u, real damage, real radius, real time, boolexpr b returns nothing
    local timer t = CreateTimer( )
    local Bezier A
    local OpalescenceS B = OpalescenceS.create( )
    local integer i
    local integer i1
    local real z = GetUnitFlyHeight( u ) + 50.00
    
    set B.x = GetUnitX( u )
    set B.y = GetUnitY( u )
    set B.caster = u
    set B.p = GetOwningPlayer( u )
    set B.b = b
    set B.damage = damage
    set B.radius = radius
    set B.time = time
    
    set z = z + GetLocZ( B.x, B.y )
    
    call ShowUnit( u, false )
    call SetUnitInvulnerable( u, true )
    
    call SaveInteger( H, GetHandleId( t ), 0, B )
    call TimerStart( t, 0.01, true, function OpalescenceDamage )
    
    set TempUnit = CreateUnit( B.p, PhaseID, B.x, B.y, GetRandomReal( 0.00, 360.00 ) )
    call SetUnitX( TempUnit, B.x )
    call SetUnitY( TempUnit, B.y )
    call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
    call SetUnitAnimation( TempUnit, "birth" )
    call UnitApplyTimedLife( TempUnit, 'BTLF', 0.50 )
    
    set TempUnit = CreateUnit( B.p, PolymorphID, B.x, B.y, GetRandomReal( 0.00, 360.00 ) )
    call SetUnitX( TempUnit, B.x )
    call SetUnitY( TempUnit, B.y )
    call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
    call SetUnitAnimation( TempUnit, "birth" )
    call UnitApplyTimedLife( TempUnit, 'BTLF', 1.00 )
    
    set TempUnit = CreateUnit( B.p, PhaseID, B.x, B.y, GetRandomReal( 0.00, 360.00 ) )
    call SetUnitX( TempUnit, B.x )
    call SetUnitY( TempUnit, B.y )
    call SetUnitScale( TempUnit, 2.00, 2.00, 2.00 )
    call SetUnitAnimation( TempUnit, "birth" )
    
    set t = CreateTimer( )
    call SaveUnitHandle( H, GetHandleId( t ), 0, TempUnit )
    call SaveReal( H, GetHandleId( t ), 1, 2.00 )
    call TimerStart( t, 0.01, true, function SetScale )
    
    set i = 20
    
    loop
        set t = CreateTimer( )
        set A = Bezier.create( )
        
        set A.pCount = 9
        
        set A.p[0] = Point.create( B.x, B.y, z )
        
        set i1 = 1
        
        loop
            set A.p[i1] = Point.create( B.x + GetRandomReal( 500.00, 600.00 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), B.y + GetRandomReal( 500.00, 600.00 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), z + GetRandomReal( 0.00, 500.00 ) )
            set A.p[i1].z = A.p[i1].z + GetLocZ( A.p[i1].x, A.p[i1].y )
            
            set i1 = i1 + 1
            exitwhen i1 >= A.pCount
        endloop
        
        set A.p[i1] = Point.create( B.x + GetRandomReal( 15.00, 30.00 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), B.y + GetRandomReal( 15.00, 30.00 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), 0.00 )
        set A.p[i1].z = A.p[i1].z + GetLocZ( A.p[i1].x, A.p[i1].y )
        
        set A.last = Point.create( A.p[0].x, A.p[0].y, A.p[0].z )
        
        set A.time = 0.00
        set A.timeMax = time
        
        set A.dummy = CreateUnit( B.p, FaerieID, A.p[0].x, A.p[0].y, GetRandomReal( 0.00, 360.00 ) )
        call UnitAddAbility( A.dummy, 'Arav' )
        call SetUnitPositionEx( A.dummy, A.p[0].x, A.p[0].y )
        call SetUnitFlyHeight( A.dummy, A.p[0].z - GetLocZ( A.p[0].x, A.p[0].y ), 0.00 )
        call SetUnitAnimation( A.dummy, "birth" )
        call QueueUnitAnimation( A.dummy, "stand" )
        
        call SaveInteger( H, GetHandleId( t ), 0, A )
        call TimerStart( t, 0.03125, true, function OpalescenceMove )
        
        set i = i - 1
        exitwhen i <= 0
    endloop
    
    set t = null
endfunction

//===========================================================================
function InitTrig_Opalescence takes nothing returns nothing
    local rect r = GetWorldBounds( )
    //set gg_trg_Opalescence = CreateTrigger(  )
    
    call SaveInteger( PascalTriangle, 0, 0, 1 )
    call SaveInteger( PascalTriangle, 1, 0, 1 )
    call SaveInteger( PascalTriangle, 1, 1, 1 )
    
    call RegistPascalTriangle( 9 )
    
    set MaxX = GetRectMaxX( r ) - 32.00
    set MinX = GetRectMinX( r ) + 32.00
    set MaxY = GetRectMaxY( r ) - 32.00
    set MinY = GetRectMinY( r ) + 32.00
    
    call RemoveRect( r )
    
    set r = null
endfunction
endlibrary

инструкция по импорту
  • скопировать триггер Opalescence и вставить в карту
  • заполнить равкоды в 7-12 строках кода Opalescence в соответствии с объектами из ро
  • создать переменную с названием TempUnit для гуи пользования
отделённые комментарием триггеры не нужны, один для гуи примера, другие для каста абилок врагов
если нужна дополнительная помощь, а-ля изменить точки полёта, формулу, эффект при уроне, больше сгустков добавить, убрать какие-то лишние элементы и т.п., без проблем сделаю или поясню как сделать самому


я не думаю что кто-то всерьёз будет этот спелл где-то использовать, так что просто демонстрирую идею
`
ОЖИДАНИЕ РЕКЛАМЫ...
33
Всю это способность можно сделать без единой строчки кода, заменив эффект у дефолтной абилки лесного дракончика. Но опять же... кто сделает такой эффект? И всё равно придётся двигать полёт элементов по Безье, только уже внутри модели, а не кодом, ну а так разумеется всё супер 👍
28
Берги, почти всю, там ещё урон есть, мряф ~
но впрочем ты прав, у меня тоже возникла мысль что это от дракончика абилка будет, у меня было в планах а-ля указывать место приземления, или как ульта талона из лиги легенд (он раскидывает сюрикены по сторонам и становится невидимым, при нанесении урона невидимость спадает а сюрикены летят в цель), но потом меня начали кушат мысли, что "а если за время полёта этих сгустков захочется поменять место приземления?", "а если кто-то найдёт ассоциацию с ультой талона?" ну и короче просто откат произошёл вот в это воть)
Чтобы оставить комментарий, пожалуйста, войдите на сайт.