Добавлен rsfghd,
опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
vJass
Тип:
Способность
Версия Warcraft:
1.26+
Пирокластическое уничтожение
Герой призывает древнее энтропическое существо, которое подготавливает мощный луч солнечного ветра, что стирает всё на своём пути
код
library PyroclasticDestructionLib
globals
private constant hashtable H = InitHashtable( )
private constant group TempGroup = CreateGroup( )
private constant group TempGroup1 = CreateGroup( )
private constant timer TempTimer = CreateTimer( )
private constant location LFZ = Location( 0.00, 0.00 )
private constant real DamagePeriodic = 0.10
private constant integer ExplosionID = 'u006'
private constant integer SalamanderID = 'u009'
private constant integer DarkRitualID = 'u00A'
private constant integer ItemStrengthGainID = 'u00B'
private constant integer MirrorImageID = 'u00C'
private constant integer ReviveHeroInstanlyID = 'u00D'
private constant integer WarStompID = 'u00E'
private constant integer SmallFlameSpawnID = 'u00F'
private constant integer DoomID = 'u00G'
private constant integer IncinerateID = 'u00H'
private constant integer Explosion90ID = 'u00I'
private constant integer FireID = 'u00J'
private constant integer ReviveHeroID = 'u00K'
private constant integer BloodLustID = 'u00L'
private constant integer RedLightOmniID = 'u00M'
private real MaxX
private real MinX
private real MaxY
private real MinY
private real TempReal = 0.00
private unit TempUnit = null
endglobals
private function GetLocZ takes real x, real y returns real
call MoveLocation( LFZ, x, y )
return GetLocationZ( LFZ )
endfunction
private function CreateUnitEx takes player id, integer unitid, real x, real y, real face returns unit
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
set TempUnit = CreateUnit( id, unitid, x, y, face )
call SetUnitX( TempUnit, x )
call SetUnitY( TempUnit, y )
return TempUnit
endfunction
private struct PyroclasticDestructionS
unit caster
unit dummy
player p
boolexpr b
real x
real y
real a
real ax
real ay
real time
real damage
endstruct
private function PyroclasticDestructionDamage takes nothing returns nothing
local PyroclasticDestructionS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
local unit u
local real x = A.x
local real y = A.y
local integer i = 8
set TempUnit = A.caster
loop
call GroupEnumUnitsInRange( TempGroup, x, y, 700.00, A.b )
loop
set u = FirstOfGroup( TempGroup )
exitwhen u == null
call GroupRemoveUnit( TempGroup, u )
if not IsUnitInGroup( u, TempGroup1 ) and IsUnitInRangeXY( u, x, y, 500.00 ) then
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
call GroupAddUnit( TempGroup1, u )
endif
endloop
set i = i - 1
exitwhen i <= 0
set x = x + 300.00 * A.ax
set y = y + 300.00 * A.ay
endloop
call GroupClear( TempGroup1 )
set A.time = A.time - DamagePeriodic
if A.time <= 0.00 then
call PauseTimer( GetExpiredTimer( ) )
call FlushChildHashtable( H, GetHandleId( GetExpiredTimer( ) ) )
call DestroyTimer( GetExpiredTimer( ) )
call SetUnitTimeScale( A.dummy, 0.30 )
call UnitApplyTimedLife( A.dummy, 'BTLF', 0.50 )
set A.dummy = null
set A.caster = null
call A.destroy( )
endif
endfunction
private function SetAnim_1 takes nothing returns nothing
local timer t = GetExpiredTimer( )
call SetUnitTimeScale( LoadUnitHandle( H, GetHandleId( t ), 0 ), 1.00 )
call FlushChildHashtable( H, GetHandleId( t ) )
call DestroyTimer( t )
set t = null
endfunction
private function ShakeCamera takes nothing returns nothing
local real richter
set TempReal = TempReal - 0.50
set richter = TempReal
if (richter > 5.0) then
set richter = 5.0
endif
if (richter < 2.0) then
set richter = 2.0
endif
call CameraSetTargetNoiseEx(TempReal*2.0, TempReal*Pow(10,richter),true)
call CameraSetSourceNoiseEx(TempReal*2.0, TempReal*Pow(10,richter),true)
if TempReal <= 0.00 then
call SetDayNightModels( "Environment\\DNC\\DNCAshenvale\\DNCAshenValeTerrain\\DNCAshenValeTerrain.mdx", "Environment\\DNC\\DNCAshenvale\\DNCAshenValeUnit\\DNCAshenValeUnit.mdx" )
call CameraSetSourceNoise(0, 0)
call CameraSetTargetNoise(0, 0)
call PauseTimer( TempTimer )
endif
endfunction
private function LightScale takes nothing returns nothing
local timer t = GetExpiredTimer( )
local integer i = GetHandleId( t )
local real r = LoadReal( H, i, 1 ) - 0.50
call SetUnitScale( LoadUnitHandle( H, i, 0 ), r, r, r )
if r <= 1.00 then
call KillUnit( LoadUnitHandle( H, i, 0 ) )
call PauseTimer( t )
call DestroyTimer( t )
call FlushChildHashtable( H, i )
else
call SaveReal( H, i, 1, r )
endif
set t = null
endfunction
private function SetAnim takes nothing returns nothing
local timer t = GetExpiredTimer( )
local PyroclasticDestructionS A = LoadInteger( H, GetHandleId( t ), 0 )
local integer i
local real x = A.x
local real y = A.y
local real richter
call TimerStart( t, DamagePeriodic, true, function PyroclasticDestructionDamage )
set i = 15
loop
call SetUnitFlyHeight( CreateUnitEx( A.p, Explosion90ID, x, y, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 5.00, 5.00, 5.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 15.00 )
call SetUnitScale( CreateUnitEx( A.p, ExplosionID, x, y, A.a * bj_RADTODEG ), 2.00, 2.00, 2.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 15.00 )
set i = i - 1
exitwhen i <= 0.00
set x = x + 150.00 * A.ax
set y = y + 150.00 * A.ay
endloop
set x = A.x
set y = A.y
set i = 5
loop
call SetUnitFlyHeight( CreateUnitEx( A.p, FireID, x, y, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 5.00, 5.00, 5.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', A.time )
set i = i - 1
exitwhen i <= 0
set x = x + 300.00 * A.ax
set y = y + 300.00 * A.ay
endloop
call SetUnitFlyHeight( CreateUnitEx( A.p, BloodLustID, A.x, A.y, 270.00 ), 300.00, 0.00 )
set t = CreateTimer( )
call SaveUnitHandle( H, GetHandleId( t ), 0, TempUnit )
call SaveReal( H, GetHandleId( t ), 1, 100.00 )
call TimerStart( t, 0.01, true, function LightScale )
set TempReal = 100.00
set richter = TempReal
if (richter > 5.0) then
set richter = 5.0
endif
if (richter < 2.0) then
set richter = 2.0
endif
call CameraSetTargetNoiseEx(TempReal*2.0, TempReal*Pow(10,richter),true)
call CameraSetSourceNoiseEx(TempReal*2.0, TempReal*Pow(10,richter),true)
call TimerStart( TempTimer, 0.01, true, function ShakeCamera )
call SetUnitFlyHeight( CreateUnitEx( A.p, SmallFlameSpawnID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 4.00, 4.00, 4.00 )
call SetUnitAnimation( TempUnit, "birth" )
call UnitApplyTimedLife( TempUnit, 'BTLF', 7.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, RedLightOmniID, A.x, A.y, 0.00 ), 50.00, 0.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', A.time )
call SetDayNightModels( "", "" )
set i = 2
loop
call SetUnitFlyHeight( CreateUnitEx( A.p, Explosion90ID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 5.00, 5.00, 5.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 15.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, IncinerateID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 5.00, 5.00, 5.00 )
call SetUnitTimeScale( TempUnit, 0.70 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, IncinerateID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 5.00, 5.00, 5.00 )
call SetUnitTimeScale( TempUnit, 0.50 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, DoomID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
call SetUnitTimeScale( TempUnit, 0.20 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, WarStompID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, WarStompID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 4.00, 4.00, 4.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, WarStompID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
call SetUnitTimeScale( TempUnit, 0.65 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, WarStompID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 4.00, 4.00, 4.00 )
call SetUnitTimeScale( TempUnit, 0.65 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, WarStompID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
call SetUnitTimeScale( TempUnit, 0.40 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, WarStompID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 4.00, 4.00, 4.00 )
call SetUnitTimeScale( TempUnit, 0.40 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, WarStompID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
call SetUnitTimeScale( TempUnit, 0.25 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, WarStompID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 4.00, 4.00, 4.00 )
call SetUnitTimeScale( TempUnit, 0.25 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, ItemStrengthGainID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
call SetUnitTimeScale( TempUnit, 0.50 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, ItemStrengthGainID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 4.00, 4.00, 4.00 )
call SetUnitTimeScale( TempUnit, 0.50 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, MirrorImageID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 3.00, 3.00, 3.00 )
call SetUnitTimeScale( TempUnit, 0.50 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SetUnitFlyHeight( CreateUnitEx( A.p, MirrorImageID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 4.00, 4.00, 4.00 )
call SetUnitTimeScale( TempUnit, 0.50 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
set i = i - 1
exitwhen i <= 0
endloop
call SetUnitFlyHeight( CreateUnitEx( A.p, ReviveHeroInstanlyID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitTimeScale( TempUnit, 7.00 )
call SetUnitScale( TempUnit, 4.00, 4.00, 4.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
set t = CreateTimer( )
call SaveUnitHandle( H, GetHandleId( t ), 0, TempUnit )
call TimerStart( t, 0.15, false, function SetAnim_1 )
call SetUnitFlyHeight( CreateUnitEx( A.p, ReviveHeroID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 4.00, 4.00, 4.00 )
call SetUnitTimeScale( TempUnit, 7.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
set t = CreateTimer( )
call SaveUnitHandle( H, GetHandleId( t ), 0, TempUnit )
call TimerStart( t, 0.15, false, function SetAnim_1 )
call SetUnitTimeScale( A.dummy, 0.10 )
set t = null
endfunction
function PyroclasticDestruction_Actions takes unit caster, real damage, real angle, boolexpr b returns nothing
local timer t = CreateTimer( )
local PyroclasticDestructionS A = PyroclasticDestructionS.create( )
set A.caster = caster
set A.damage = damage
set A.b = b
set A.p = GetOwningPlayer( A.caster )
set A.x = GetUnitX( A.caster )
set A.y = GetUnitY( A.caster )
set A.a = angle * bj_DEGTORAD
set A.ax = Cos( A.a )
set A.ay = Sin( A.a )
set A.time = 2.00
set A.dummy = CreateUnitEx( A.p, SalamanderID, A.x - 500.00 * A.ax, A.y - 500.00 * A.ay, A.a * bj_RADTODEG )
call SetUnitVertexColor( A.dummy, 255, 200, 200, 100 )
call SetUnitScale( A.dummy, 3.00, 3.00, 3.00 )
call SetUnitTimeScale( A.dummy, 0.50 )
call SetUnitAnimation( A.dummy, "attack" )
call QueueUnitAnimation( A.dummy, "stand" )
call SetUnitFlyHeight( CreateUnitEx( A.p, DarkRitualID, A.x - 100.00 * A.ax, A.y - 100.00 * A.ay, A.a * bj_RADTODEG ), 50.00, 0.00 )
call SetUnitScale( TempUnit, 2.00, 2.00, 2.00 )
call UnitApplyTimedLife( TempUnit, 'BTLF', 5.00 )
call SaveInteger( H, GetHandleId( t ), 0, A )
call TimerStart( t, 1.00, false, function SetAnim )
set t = null
endfunction
//===========================================================================
function InitTrig_PyroclasticDestruction takes nothing returns nothing
local rect r = GetWorldBounds( )
//set gg_trg_PyroclasticDestruction = CreateTrigger( )
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
инструкция по импорту
- скопировать триггер PyroclasticDestruction и вставить в карту
- заполнить равкоды в триггере PyroclasticDestruction в соответствии с названиями переменных
- создать переменную с названием TempUnit для гуи пользования
отделённые комментарием триггеры не нужны, один для показа урона, другой для гуи примера
если нужна дополнительная помощь, а-ля изменить радиус урона, формулу, дистанцию, добавить эффект при уроне, настроить днс модель, убрать какие-то лишние элементы и т.п., без проблем сделаю или поясню как сделать самому
в карте присутствует отредактированная модель источника освещения
upd я не думаю что кто-то всерьёз (мб гуишники) будет этот спелл где-то использовать, так что просто демонстрирую идею
upd 11.01.2024 немного оптимизированная версия, даммики кроме огня не попадают в перебор группы, для лучшей оптимизации можно увеличить периодичность урона либо шаг поиска целей, а так же уйти нафиг с гуи булекспром)
для ещё большей оптимизации можно попробовать переработать выбор юнитов в группу и нанесения урона, т.е.:
для ещё большей оптимизации можно попробовать переработать выбор юнитов в группу и нанесения урона, т.е.:
код
globals
private constant group TempGroup = CreateGroup
private boolexpr Cond = null
private unit bj_lastFilterUnit = null
private real TempX = 0.00
private real TempY = 0.00
endglobals
native UnitAlive takes unit id returns boolean
...
private function DamageCond takes nothing returns boolean
set bj_lastFilterUnit = GetFilterUnit( )
return UnitAlive( bj_lastFilterUnit ) and IsUnitEnemy( bj_lastFilterUnit, bj_groupEnumOwningPlayer ) and IsUnitInRangeXY( bj_lastFilterUnit, TempX, TempY, 500.00 )
endfunction
...
set Cond = Condition( function DamageCond )
...
set bj_groupEnumOwningPlayer = GetOwningPlayer( A.caster )
set TempX = A.x
set TempY = A.y
set i = 8
loop
call GroupEnumUnitsInRange( TempGroup, TempX, TempY, 700.00, Cond )
set i = i - 1
exitwhen i <= 0
set TempX = TempX + 300.00 * A.ax
set TempY = TempY + 300.00 * A.ay
endloop
loop
set u = FirstOfGroup( TempGroup )
exitwhen u == null
call GroupRemoveUnit( TempGroup, u )
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
endloop
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
с таким количеством эффектов 2+ кастов действительно могут вызвать просадку, хотя у меня есть подозрения что функция GroupEnumUnitsInRange выбирает мёртвых москитов
можно заменю видео в ресурсе на твоё?)
так бы я на ютуб бы залил, но смысла не было этого делать, не моя работа же
рес обновлён
Отредактирован Daro
можно конечно более грамотно переписать с созданием одного таймера и циклом перебирать индекс структуры, всю библиотеку в неё засунуть и оперировать методами, но мне просто лень, да и исходя из разговора с анрайзом так и не понятно что лучше, привязка структуры к локальному таймеру или перебор структур циклом с глобальным таймером, оно какое-то анизотропное (надо будет снова спросить)