Опалесценция
(атакующая)
Герой посылает пучок света, который взрывается над выбранной областью вызывая флуктуацию из световых частиц, что наносит урон вражеской нежити и замедляет противников в области на время действия эффекта
код
library OpalescenceLib
globals
constant hashtable H = InitHashtable( )
constant location LFZ = Location( 0.00, 0.00 )
private constant group TempGroup = CreateGroup( )
private constant integer HealingID = 'u005'
private constant integer AbolishID = 'u006'
private constant integer FaerieID = 'u000'
private constant integer PhaseID = 'u003'
private constant integer WispID = 'u002'
private unit TempUnit = null
private real MaxX
private real MinX
private real MaxY
private real MinY
private string array AttachPointName
endglobals
native UnitAlive takes unit id returns boolean
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
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
private struct OpalescenceMoveS
timer t
unit dummy
real time
real timeMax
vector array l[6]
vector last
endstruct
private struct OpalescenceS
timer t
unit dummy
unit caster
player p
vector v
vector l
vector endPos
real speed
real damage
real radius
real time
real timeThreshold
endstruct
private function OpalescenceMove takes nothing returns nothing
local OpalescenceMoveS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
local integer i = 0
local integer k = 0
local real array x
local real array y
local real array z
local real r
local unit u
set A.time = A.time + 0.03125 / A.timeMax
if A.time > 1.00 then
set A.time = 1.00
endif
loop
set x[k] = A.l[k].x
set y[k] = A.l[k].y
set z[k] = A.l[k].z
set k = k + 1
exitwhen k >= 6
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 > 6 - k
endloop
set k = k + 1
exitwhen k >= 6 - 1
endloop
call SetUnitPositionEx( A.dummy, x[0], y[0] )
call SetUnitFlyHeight( A.dummy, z[0] - GetLocZ( x[0], y[0] ), 0.00 )
call SetUnitFacing( A.dummy, Atan2( y[0] - A.last.y, x[0] - A.last.x ) * bj_RADTODEG )
if A.time >= 1.00 then
call PauseTimer( A.t )
call FlushChildHashtable( H, GetHandleId( A.t ) )
call DestroyTimer( A.t )
call UnitApplyTimedLife( A.dummy, 'BTLF', 2.00 )
call SetUnitAnimation( A.dummy, "death" )
set i = 0
loop
call A.l[i].destroy( )
set i = i + 1
exitwhen i >= 6
endloop
call A.last.destroy( )
set A.t = null
set A.dummy = null
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 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 A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
local OpalescenceMoveS B
local unit u
local real x
local real y
local timer t
local integer i
local integer j
if A.timeThreshold > 0.00 then
set A.timeThreshold = A.timeThreshold - 0.01
if A.timeThreshold == 0.20 then
set TempUnit = CreateUnit( A.p, WispID, A.l.x + A.speed * 20.00 * A.v.x, A.l.y + A.speed * 20.00 * A.v.y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( TempUnit, 'Arav' )
call SetUnitPositionEx( TempUnit, A.l.x + A.speed * 20.00 * A.v.x, A.l.y + A.speed * 20.00 * A.v.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, A.time - 2.00 ) )
endif
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 SetUnitPositionEx( A.dummy, A.l.x, A.l.y )
call SetUnitFlyHeight( A.dummy, A.l.z - GetLocZ( A.l.x, A.l.y ), 0.00 )
if A.timeThreshold <= 0.00 then
call UnitApplyTimedLife( A.dummy, 'BTLF', 0.30 )
call SetUnitAnimation( A.dummy, "death" )
call TimerStart( A.t, 0.05, true, function OpalescenceDamage )
set TempUnit = CreateUnit( A.p, PhaseID, A.l.x, A.l.y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( TempUnit, 'Arav' )
call SetUnitPositionEx( TempUnit, A.l.x, A.l.y )
call SetUnitFlyHeight( TempUnit, 300.00, 0.00 )
call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
call SetUnitAnimation( A.dummy, "birth" )
call QueueUnitAnimation( A.dummy, "stand" )
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( A.p, HealingID, A.l.x, A.l.y, GetRandomReal( 0.00, 360.00 ) )
call SetUnitPositionEx( TempUnit, A.l.x, A.l.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( A.p, PhaseID, A.l.x, A.l.y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( TempUnit, 'Arav' )
call SetUnitPositionEx( TempUnit, A.l.x, A.l.y )
call SetUnitFlyHeight( TempUnit, 300.00, 0.00 )
call SetUnitScale( TempUnit, 2.00, 2.00, 2.00 )
call SetUnitAnimation( A.dummy, "birth" )
call QueueUnitAnimation( A.dummy, "stand" )
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 t = null
set i = 10
loop
set B = OpalescenceMoveS.create( )
set B.t = CreateTimer( )
set B.l[0] = vector.create( A.l.x + GetRandomReal( A.radius * 0.25, A.radius * 1.25 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), A.l.y + GetRandomReal( A.radius * 0.25, A.radius * 1.25 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), 0.00 )
set TempUnit = CreateUnit( A.p, FaerieID, B.l[0].x, B.l[0].y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( TempUnit, 'Arav' )
call SetUnitPositionEx( TempUnit, B.l[0].x, B.l[0].y )
call SetUnitFlyHeight( TempUnit, GetRandomReal( 0.00, 100.00 ), 0.00 )
call SetUnitAnimation( TempUnit, "death" )
call UnitApplyTimedLife( TempUnit, 'BTLF', 1.00 )
set B.l[0].x = A.l.x + GetRandomReal( 15.00, 50.00 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) )
set B.l[0].y = A.l.y + GetRandomReal( 15.00, 50.00 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) )
set B.l[0].z = GetLocZ( B.l[0].x, B.l[0].y ) + GetRandomReal( 400.00, 600.00 )
set j = 1
loop
set B.l[j] = vector.create( A.l.x + GetRandomReal( A.radius * 1.80, A.radius * 2.00 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), A.l.y + GetRandomReal( A.radius * 1.80, A.radius * 2.00 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), 0.00 )
set B.l[j].z = GetLocZ( B.l[j].x, B.l[j].y ) + GetRandomReal( -100.00, 650.00 )
set j = j + 1
exitwhen j >= 5
endloop
set B.l[j] = vector.create( A.l.x + GetRandomReal( A.radius * 0.80, A.radius ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), A.l.y + GetRandomReal( A.radius * 0.80, A.radius ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), 0.00 )
set B.l[j].z = GetLocZ( B.l[j].x, B.l[j].y ) + GetRandomReal( 50.00, 100.00 )
set B.last = vector.create( B.l[0].x, B.l[0].y, B.l[0].z )
set B.time = 0.00
set B.timeMax = 0.70
set B.dummy = CreateUnit( A.p, FaerieID, B.l[0].x, B.l[0].y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( B.dummy, 'Arav' )
call SetUnitPositionEx( B.dummy, B.l[0].x, B.l[0].y )
call SetUnitFlyHeight( B.dummy, B.l[0].z - GetLocZ( B.l[0].x, B.l[0].y ), 0.00 )
call SetUnitAnimation( B.dummy, "birth" )
call QueueUnitAnimation( B.dummy, "stand" )
call SetUnitVertexColor( B.dummy, 255, 255, 255, 0 )
call SaveInteger( H, GetHandleId( B.t ), 0, B )
call TimerStart( B.t, 0.03125, true, function OpalescenceMove )
set i = i - 1
exitwhen i < 0
endloop
endif
else
set A.time = A.time - 0.05
call GroupEnumUnitsInRange( TempGroup, A.l.x, A.l.y, A.radius + 200.00, null )
loop
set u = FirstOfGroup( TempGroup )
exitwhen u == null
call GroupRemoveUnit( TempGroup, u )
if IsUnitInRangeXY( u, A.l.x, A.l.y, A.radius ) then
if UnitAlive( u ) and IsUnitEnemy( u, A.p ) then
call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Items\\WandOfNeutralization\\NeutralizationMissile.mdl", u, AttachPointName[GetRandomInt( 0, 5 )] ) )
if A.damage >= 0.00 then
call UnitDamageTarget( A.caster, u, A.damage, false, false, null, null, null )
endif
endif
endif
endloop
if A.time >= 0.70 then
set B = OpalescenceMoveS.create( )
set B.t = CreateTimer( )
set B.l[0] = vector.create( A.l.x + GetRandomReal( A.radius * 0.25, A.radius * 1.25 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), A.l.y + GetRandomReal( A.radius * 0.25, A.radius * 1.25 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), 0.00 )
set TempUnit = CreateUnit( A.p, FaerieID, B.l[0].x, B.l[0].y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( TempUnit, 'Arav' )
call SetUnitPositionEx( TempUnit, B.l[0].x, B.l[0].y )
call SetUnitFlyHeight( TempUnit, GetRandomReal( 0.00, 100.00 ), 0.00 )
call SetUnitAnimation( TempUnit, "death" )
call UnitApplyTimedLife( TempUnit, 'BTLF', 1.00 )
set B.l[0].x = A.l.x + GetRandomReal( 15.00, 50.00 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) )
set B.l[0].y = A.l.y + GetRandomReal( 15.00, 50.00 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) )
set B.l[0].z = GetLocZ( B.l[0].x, B.l[0].y ) + GetRandomReal( 400.00, 600.00 )
set j = 1
loop
set B.l[j] = vector.create( A.l.x + GetRandomReal( A.radius * 1.80, A.radius * 2.00 ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), A.l.y + GetRandomReal( A.radius * 1.80, A.radius * 2.00 ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), 0.00 )
set B.l[j].z = GetLocZ( B.l[j].x, B.l[j].y ) + GetRandomReal( -100.00, 650.00 )
set j = j + 1
exitwhen j >= 5
endloop
set B.l[j] = vector.create( A.l.x + GetRandomReal( A.radius * 0.80, A.radius ) * Cos( GetRandomReal( -bj_PI, bj_PI ) ), A.l.y + GetRandomReal( A.radius * 0.80, A.radius ) * Sin( GetRandomReal( -bj_PI, bj_PI ) ), 0.00 )
set B.l[j].z = GetLocZ( B.l[j].x, B.l[j].y ) + GetRandomReal( 50.00, 100.00 )
set B.last = vector.create( B.l[0].x, B.l[0].y, B.l[0].z )
set B.time = 0.00
set B.timeMax = 0.70
set B.dummy = CreateUnit( A.p, FaerieID, B.l[0].x, B.l[0].y, GetRandomReal( 0.00, 360.00 ) )
call UnitAddAbility( B.dummy, 'Arav' )
call SetUnitPositionEx( B.dummy, B.l[0].x, B.l[0].y )
call SetUnitFlyHeight( B.dummy, B.l[0].z - GetLocZ( B.l[0].x, B.l[0].y ), 0.00 )
call SetUnitAnimation( B.dummy, "birth" )
call QueueUnitAnimation( B.dummy, "stand" )
call SetUnitVertexColor( B.dummy, 255, 255, 255, 0 )
call SaveInteger( H, GetHandleId( B.t ), 0, B )
call TimerStart( B.t, 0.03125, true, function OpalescenceMove )
elseif A.time <= 0.00 then
call PauseTimer( A.t )
call FlushChildHashtable( H, GetHandleId( A.t ) )
call DestroyTimer( A.t )
set A.t = null
set A.dummy = null
set A.caster = null
call A.l.destroy( )
call A.v.destroy( )
call A.endPos.destroy( )
call A.destroy( )
endif
endif
endfunction
function Opalescence_Actions takes nothing returns nothing
local OpalescenceS A = OpalescenceS.create( )
set A.t = CreateTimer( )
set A.caster = GetTriggerUnit( )
set A.p = GetOwningPlayer( A.caster )
set A.damage = 5.00 // пошкодження
set A.radius = 400.00 // радіус
set A.time = 4.00 // час
set A.timeThreshold = 0.70
set A.l = vector.create( GetUnitX( A.caster ), GetUnitY( A.caster ), 0.00 )
set A.l.z = GetLocZ( A.l.x, A.l.y )
set A.endPos = vector.create( GetSpellTargetX( ), GetSpellTargetY( ), 0.00 )
set A.endPos.z = GetLocZ( A.endPos.x, A.endPos.y ) + 300.00
set A.v = vector.create( A.endPos.x - A.l.x, A.endPos.y - A.l.y, A.endPos.z - A.l.z )
set A.speed = A.v.length( ) * 1.30 * 0.01
call A.v.normalize( )
set A.dummy = CreateUnit( A.p, AbolishID, A.l.x, A.l.y, Atan2( A.v.y, A.v.x ) * bj_RADTODEG )
call UnitAddAbility( A.dummy, 'Arav' )
call SetUnitX( A.dummy, A.l.x )
call SetUnitY( A.dummy, A.l.y )
call SetUnitScale( A.dummy, 2.00, 2.00, 2.00 )
call UnitApplyTimedLife( A.dummy, 'BTLF', 1.00 )
call SetUnitAnimation( A.dummy, "birth" )
call QueueUnitAnimation( A.dummy, "stand" )
call SaveInteger( H, GetHandleId( A.t ), 0, A )
call TimerStart( A.t, 0.01, true, function OpalescenceDamage )
endfunction
//===========================================================================
function Opalescence_Conditions takes nothing returns boolean
return GetSpellAbilityId( ) == 'A000'
endfunction
function InitTrig_Opalescence takes nothing returns nothing
local rect r = GetWorldBounds( )
set gg_trg_Opalescence = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Opalescence, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Opalescence, Condition( function Opalescence_Conditions ) )
call TriggerAddAction( gg_trg_Opalescence, function Opalescence_Actions )
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"
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)