Ещё одна способность Бурана, но в этот раз Цветного!
Видео
Код
Для понимания сути происходящего ознакомьтесь с предыдущим ресурсом.
//DestroyEffect( AddSpecialEffect ) - создаётся эффект и сразу же удаляется, проигрывая свою анимацию смерти (чтоб уместить всё в одну строку)
globals
hashtable HT = InitHashtable() //Создаётся хэш-таблица
group Group = CreateGroup() //Создаём группу, которую будем использовать для моментальной выборки юнитов
unit Caster //Создаётся переменная для кастеров
unit Target //Создаётся переменная для целей
real CastX //Создаётся переменная для точки каста Y
real CastY //Создаётся переменная для точки каста X
timer Timer //Создаётся переменная для таймеров
integer TimerId //Создаётся переменная для хэндл-айди таймеров
integer Tick //Создаётся переменная для записи тика таймера
constant integer Blizzard_Id = 'A000'
constant real Blizzard_Range = 150
constant real Blizzard_Damage = 30
endglobals
native UnitAlive takes unit id returns boolean
function Blizzard_Group takes nothing returns nothing
set Target = GetEnumUnit()
if UnitAlive( Target ) and IsUnitEnemy( Target, GetOwningPlayer( Caster ) ) and not IsUnitType( Target, UNIT_TYPE_STRUCTURE ) then
call UnitDamageTarget( Caster, Target, Blizzard_Damage, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS )
endif
endfunction
function Blizzard_Timer takes nothing returns nothing
local integer lastTick
local integer xKey
local integer yKey
set Timer = GetExpiredTimer()
set TimerId = GetHandleId( Timer )
set Caster = LoadUnitHandle( HT, TimerId, 'cstr' )
set CastX = LoadReal( HT, TimerId, 'cstX' )
set CastY = LoadReal( HT, TimerId, 'cstY' )
set Tick = LoadInteger( HT, TimerId, 'tick' ) //Выгрузка в Tick счёт тиков таймера
call SaveInteger( HT, TimerId, 'tick', Tick + 1 ) //Сохранение тик таймера в хэш таблицу по дочернему ключу tick
set lastTick = LoadInteger( HT, TimerId, 'last' ) //Выгруза в lastTick последний тик таймера (смещается на 8 вперёд, за 8 тиков эффект падает на землю)
if not LoadBoolean( HT, TimerId, 'ends' ) then //Если флаг сохранённый под дочерним ключем ends = false (изначально будет false ибо при чтении отсутствующего значения всегда возвращается 0 который в случае boolean интерпретируется как false) то спелл продолжает работу
set CastX = CastX + Blizzard_Range * GetRandomReal( -1, 1 ) //Спавн эффекта в случайной точке в квадрате размером 300 (Для простоты рассчётов используется квадрат вместо окружности)
set CastY = CastY + Blizzard_Range * GetRandomReal( -1, 1 ) //Спавн эффекта в случайной точке в квадрате размером 300 (Для простоты рассчётов используется квадрат вместо окружности)
set lastTick = Tick + 8 //Смещение lastTick вперёд на 8 от текущего тика (что-бы урон проходил когда эффекты успевают падать)
call SaveInteger( HT, TimerId, 'last', lastTick )
set xKey = lastTick * 2 //запись в xKey = lastTick * 2 (xKey - по сути ключ созданный для удобства получения координаты X на 8 тиков позже)
set yKey = xKey + 1 //запись в yKey = xKey + 1 (yKey - по сути ключ созданный для удобства получения координаты Y на 8 тиков позже)
call SaveReal( HT, TimerId, xKey, CastX )
call SaveReal( HT, TimerId, yKey, CastY )
if GetRandomInt( 0, 1 ) == 0 then
call DestroyEffect( AddSpecialEffect( "Rain of Fire.mdx", CastX, CastY ) )
else
call DestroyEffect( AddSpecialEffect( "Rain of Fire Fel.mdx", CastX, CastY ) )
endif
endif
set xKey = Tick * 2 //Запись в xKey = Tick * 2 (для получения координаты X для текущего тика (координата которую мы сохраняли 8 тиков назад))
set yKey = xKey + 1 //Запись в yKey = xKey + 1 (для получения координаты X для текущего тика (координата которую мы сохраняли 8 тиков назад))
if HaveSavedReal( HT, TimerId, xKey ) then //Условие что значение X найдено (дополнительная проверка на Y не имеет смысла)
call GroupEnumUnitsInRange( Group, LoadReal( HT, TimerId, xKey ), LoadReal( HT, TimerId, yKey ), Blizzard_Range, null )
call ForGroup( Group, function Blizzard_Group )
call GroupClear( Group )
endif
if GetUnitCurrentOrder( Caster ) != OrderId( "Blizzard" ) then
//if GetUnitCurrentOrder( Caster ) != 0xd0079 then - этот вариант работает быстрее, так как использует id приказа без лишней возни со строками (без OrderId)
call SaveBoolean( HT, TimerId, 'ends', true ) //Сохранение в хэш-таблицу флага под дочерним ключем ends = true
endif
if LoadBoolean( HT, TimerId, 'ends' ) and Tick >= lastTick then //Условие что флаг сохранненый под дочерним ключем ends = true
call PauseTimer( Timer )
call DestroyTimer( Timer )
call FlushChildHashtable( HT, TimerId )
endif
endfunction
function Blizzard_Actions takes nothing returns nothing
if GetSpellAbilityId() == Blizzard_Id then
set Timer = CreateTimer()
set TimerId = GetHandleId( Timer )
call SaveUnitHandle( HT, TimerId, 'cstr', GetTriggerUnit() )
call SaveReal( HT, TimerId, 'cstX', GetSpellTargetX() )
call SaveReal( HT, TimerId, 'cstY', GetSpellTargetY() )
call SaveInteger( HT, TimerId, 'time', 0 )
call TimerStart( Timer, 0.1, true, function Blizzard_Timer )
endif
endfunction
function InitTrig_Blizzard takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent( t, Player( i ), EVENT_PLAYER_UNIT_SPELL_EFFECT, null )
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction( t, function Blizzard_Actions )
set t = null
call FogEnable( false )
call FogMaskEnable( false )
endfunction
Ред. nazarpunk
Ред. nazarpunk
Ред. nazarpunk
Ред. nazarpunk
Ред. nazarpunk
Ред. Meddin