Опалесценция
(атакующая)
Герой посылает пучок света, который взрывается над выбранной областью вызывая флуктуацию из световых частиц, что наносит урон вражеской нежити и замедляет противников в области на время действия эффекта
код
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 WispID = 'u002'
private constant integer PhaseID = 'u003'
private constant integer HealingID = 'u005'
private constant integer AbolishID = 'u006'
private integer PascalTriangleRows = 2
private unit TempUnit = null
private real MaxX
private real MinX
private real MaxY
private real MinY
private string array AttachPointName
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
integer pCount
real time
real timeMax
Point array p[6]
Point last
endstruct
private struct OpalescenceS
unit dummy
unit caster
player p
boolexpr b
Point pos
Point trg
real ax
real ay
real speed
real damage
real radius
real time
real timeThreshold
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 SetScale_1 takes nothing returns nothing
local timer t = GetExpiredTimer( )
local integer i = GetHandleId( t )
local real r = LoadReal( H, i, 1 ) + 0.35
if r >= 15.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 SetUnitVertexColor( LoadUnitHandle( H, i, 0 ), 255, 255, 255, R2I( 255.00 * ( 1.00 - r / 15.00 ) ) )
call SaveReal( H, i, 1, r )
endif
set t = null
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.05
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
private function OpalescenceDamage takes nothing returns nothing
local OpalescenceS B = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
local Bezier A
local unit u
local timer t
local integer i
local integer i1
local real x
local real y
if B.timeThreshold > 0.00 then
if B.timeThreshold == 0.20 then
set TempUnit = CreateUnit( B.p, WispID, B.trg.x, B.trg.y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( TempUnit, 'Arav' )
call SetUnitPositionEx( B.dummy, B.trg.x, B.trg.y )
call SetUnitFlyHeight( TempUnit, 300.00, 0.00 )
call SetUnitScale( TempUnit, 2.00, 2.00, 2.00 )
call SetUnitTimeScale( TempUnit, 2.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', RMaxBJ( 1.50, B.time - 2.00 ) )
endif
set B.timeThreshold = B.timeThreshold - 0.01
set B.pos.x = B.pos.x + B.speed * B.ax
set B.pos.y = B.pos.y + B.speed * B.ay
set B.pos.z = B.pos.z + 2.00
call SetUnitPositionEx( B.dummy, B.pos.x, B.pos.y )
call SetUnitFlyHeight( B.dummy, B.pos.z - GetLocZ( B.pos.x, B.pos.y ), 0.00 )
if B.timeThreshold <= 0.00 then
call UnitApplyTimedLife( B.dummy, 'BTLF', 0.30 )
set B.dummy = null
call B.pos.destroy( )
set TempUnit = CreateUnit( B.p, PhaseID, B.trg.x, B.trg.y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( TempUnit, 'Arav' )
call SetUnitPositionEx( TempUnit, B.trg.x, B.trg.y )
call SetUnitFlyHeight( TempUnit, 300.00, 0.00 )
call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
call SetUnitAnimation( TempUnit, "birth" )
call UnitApplyTimedLife( TempUnit, 'BTLF', 0.50 )
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 TempUnit = CreateUnit( B.p, HealingID, B.trg.x, B.trg.y, GetRandomReal( 0.00, 360.00 ) )
call SetUnitPositionEx( TempUnit, B.trg.x, B.trg.y )
call SetUnitScale( TempUnit, 2.00, 2.00, 2.00 )
call SetUnitAnimation( TempUnit, "death" )
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_1 )
set TempUnit = CreateUnit( B.p, PhaseID, B.trg.x, B.trg.y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( TempUnit, 'Arav' )
call SetUnitPositionEx( TempUnit, B.trg.x, B.trg.y )
call SetUnitFlyHeight( TempUnit, 300.00, 0.00 )
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 = 10
loop
set t = CreateTimer( )
set A = Bezier.create( )
set A.pCount = 5
set x = B.trg.x + GetRandomReal( B.radius * 0.25, B.radius * 1.25 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) )
set y = B.trg.y + GetRandomReal( B.radius * 0.25, B.radius * 1.25 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) )
set TempUnit = CreateUnit( B.p, FaerieID, x, y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( TempUnit, 'Arav' )
call SetUnitPositionEx( TempUnit, x, y )
call SetUnitFlyHeight( TempUnit, GetRandomReal( 0.00, 100.00 ), 0.00 )
call SetUnitAnimation( TempUnit, "death" )
call UnitApplyTimedLife( TempUnit, 'BTLF', 1.00 )
set A.p[0] = Point.create( B.trg.x + GetRandomReal( 15.00, 50.00 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), B.trg.y + GetRandomReal( 15.00, 50.00 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), GetRandomReal( 400.00, 600.00 ) )
set A.p[0].z = A.p[0].z + GetLocZ( A.p[0].x, A.p[0].y )
set i1 = 1
loop
set A.p[i1] = Point.create( B.trg.x + GetRandomReal( B.radius * 1.80, B.radius * 2.00 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), B.trg.y + GetRandomReal( B.radius * 1.80, B.radius * 2.00 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), GetRandomReal( -100.00, 650.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.trg.x + GetRandomReal( B.radius * 0.25, B.radius * 1.25 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), B.trg.y + GetRandomReal( B.radius * 0.25, B.radius * 1.25 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), GetRandomReal( -50.00, 100.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 = 0.70
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 SetUnitVertexColor( A.dummy, 255, 255, 255, 0 )
call SaveInteger( H, GetHandleId( t ), 0, A )
call TimerStart( t, 0.03125, true, function OpalescenceMove )
set i = i - 1
exitwhen i < 0
endloop
call TimerStart( GetExpiredTimer( ), 0.05, true, function OpalescenceDamage )
set t = null
endif
else
set B.time = B.time - 0.05
set udg_TempUnit = B.caster
call GroupEnumUnitsInRange( TempGroup, B.trg.x, B.trg.y, B.radius + 200.00, B.b )
loop
set u = FirstOfGroup( TempGroup )
exitwhen u == null
call GroupRemoveUnit( TempGroup, u )
if IsUnitInRangeXY( u, B.trg.x, B.trg.y, B.radius ) then
call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Items\\WandOfNeutralization\\NeutralizationMissile.mdl", u, AttachPointName[GetRandomInt( 0, 5 )] ) )
if B.damage >= 0.00 then
call UnitDamageTarget( B.caster, u, B.damage, false, false, null, null, null )
else
call SetWidgetLife( u, GetWidgetLife( u ) - B.damage )
endif
endif
endloop
if B.time >= 0.70 then
set t = CreateTimer( )
set A = Bezier.create( )
set A.pCount = 5
set A.p[0] = Point.create( B.trg.x + GetRandomReal( 15.00, 50.00 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), B.trg.y + GetRandomReal( 15.00, 50.00 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), 300.00 )
set A.p[0].z = A.p[0].z + GetLocZ( A.p[0].x, A.p[0].y )
set i1 = 1
loop
set A.p[i1] = Point.create( B.trg.x + GetRandomReal( B.radius * 1.80, B.radius * 2.00 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), B.trg.y + GetRandomReal( B.radius * 1.80, B.radius * 2.00 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), GetRandomReal( -100.00, 650.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.trg.x + GetRandomReal( B.radius * 0.25, B.radius * 1.25 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), B.trg.y + GetRandomReal( B.radius * 0.25, B.radius * 1.25 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), GetRandomReal( -50.00, 100.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 = 0.70
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 SetUnitVertexColor( A.dummy, 255, 255, 255, 0 )
call SaveInteger( H, GetHandleId( t ), 0, A )
call TimerStart( t, 0.03125, true, function OpalescenceMove )
set t = null
elseif B.time <= 0.00 then
set t = GetExpiredTimer( )
call PauseTimer( t )
call FlushChildHashtable( H, GetHandleId( t ) )
call DestroyTimer( t )
set t = null
set B.caster = null
call B.trg.destroy( )
call B.destroy( )
endif
endif
endfunction
function Opalescence_Actions takes unit u, real damage, real radius, real time, boolexpr b returns nothing
local timer t = CreateTimer( )
local OpalescenceS A = OpalescenceS.create( )
set A.caster = u
set A.p = GetOwningPlayer( u )
set A.b = b
set A.damage = damage
set A.radius = radius
set A.time = time
set A.timeThreshold = 0.70
set A.pos = Point.create( GetUnitX( u ), GetUnitY( u ), 0.00 )
set A.pos.z = A.pos.z + GetLocZ( A.pos.x, A.pos.y )
set A.trg = Point.create( GetSpellTargetX( ), GetSpellTargetY( ), 0.00 )
set A.trg.z = A.trg.z + GetLocZ( A.trg.x, A.trg.y )
set A.ax = Atan2( A.trg.y - A.pos.y, A.trg.x - A.pos.x )
set A.ay = Sin( A.ax )
set A.ax = Cos( A.ax )
set A.speed = SquareRoot( ( A.trg.x - A.pos.x ) * ( A.trg.x - A.pos.x ) + ( A.trg.y - A.pos.y ) * ( A.trg.y - A.pos.y ) ) * 1.30 * 0.01
set A.dummy = CreateUnit( A.p, AbolishID, A.pos.x, A.pos.y, Atan2( A.ay, A.ax ) * bj_RADTODEG )
call UnitAddAbility( A.dummy, 'Arav' )
call SetUnitX( A.dummy, A.pos.x )
call SetUnitY( A.dummy, A.pos.y )
call SetUnitScale( A.dummy, 2.00, 2.00, 2.00 )
call UnitApplyTimedLife( A.dummy, 'BTLF', 1.00 )
call SaveInteger( H, GetHandleId( t ), 0, A )
call TimerStart( t, 0.01, true, function OpalescenceDamage )
set t = null
endfunction
//===========================================================================
function InitTrig_Opalescence takes nothing returns nothing
local rect r = GetWorldBounds( )
//set gg_trg_Opalescence = CreateTrigger( )
set AttachPointName[0] = "chest"
set AttachPointName[1] = "head"
set AttachPointName[2] = "left hand"
set AttachPointName[3] = "right hand"
set AttachPointName[4] = "left foot"
set AttachPointName[5] = "right foot"
call SaveInteger( PascalTriangle, 0, 0, 1 )
call SaveInteger( PascalTriangle, 1, 0, 1 )
call SaveInteger( PascalTriangle, 1, 1, 1 )
call RegistPascalTriangle( 5 )
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-11 строках кода Opalescence в соответствии с объектами из ро
- создать переменную с названием TempUnit для гуи пользования
отделённые комментарием триггеры не нужны, один для гуи примера, другой для показа урона
если нужна дополнительная помощь, а-ля изменить точки полёта, формулу, эффект при уроне, больше сгустков добавить, убрать какие-то лишние элементы и т.п., без проблем сделаю или поясню как сделать самому
я не думаю что кто-то всерьёз будет этот спелл где-то использовать, так что просто демонстрирую идею
P0 * (1-t)^3 + P1 * t * (1-t)^2 + P2 * t^2 * (1-t) + P3 * t^3
думаешь рассчёт в цикле может вызывать лаги?)
возможно, единственная функция которая вызывает просадку из предложенного тобой варианта это Pow, я не знаю насколько она ресурсоёмкая, да и с каждым увеличением опорной точки твоя полинома будет расти, из-за чего удобнее для читаемости перенести уже в цикл
у меня лично лагает от количества снарядов, периодичности и весомо перебор группы, тем более когда гуи юзается
и всё же лучшим вариантом будет воспользоваться оптимизированной версией, даже в проверке фпс разница была в 40% где-то (45 и 65)