Простое заклинание для новичков. Добавляет к стандартному Бурану дополнительный AOE урон раз в секунду. Код намеренно упрощён из-за обучающего характера материала. Более продвинутую версию можете посмотреть по следущей ссылке.
Видео
Код
//1. Обнуление глобалок не имеет смысла (только если вы уверены что она не будет больше вызыватся, тогда ради перфекционизма можно обнулить)
//2. Обнулять локальные переменные нужно обязательно, можно не обнулять integer, real, string (тут сам не знаю)
//3. Спелл сделан без кастомных функций, попытался более менее разъяснить о функциях для новичков, если где-то какая то ошибка, просьба отписать о ней)
//4. Итерация (повторение) - повторение таймера или цикла (тут таймер повторяется раз в 1 секунду, то есть раз в 1 секунду происходит итерация таймера)
globals //Начало глобальных переменных
hashtable HT = InitHashtable() //Создаётся хэш-таблица
group Group = CreateGroup() //Создаём группу, которую будем использовать для моментальной выборки юнитов
unit Caster //Создаётся переменная для кастеров
unit Target //Создаётся переменная для целей
timer Timer //Создаётся переменная для таймеров
integer TimerId //Создаётся переменная для хэндл-айди таймеров
//Константы для удобства изменения параметров способности
constant integer Blizzard_Id = 'A000' //Равкод способности
constant real Blizzard_Range = 300 //Область воздействия способности
constant real Blizzard_Damage = 30 //Урон способности
endglobals //Конец глобальных переменных
native UnitAlive takes unit id returns boolean //Объявляется функция с проверкой на то что юнит жив, если не объявить, то и юзать не получится
function Blizzard_Group takes nothing returns nothing //Функция группы (фильтрация и нанесение урона)
set Target = GetEnumUnit() //В переменную Target записывается выбираемый из группы юнит
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 ) //Наносит 300 урона отфильтрованным юнитам (врагам)
endif //Конец условия
endfunction
function Blizzard_Timer takes nothing returns nothing //Функция для таймера
set Timer = GetExpiredTimer() //В Timer записывается истекающий таймер
set TimerId = GetHandleId( Timer ) //в TimerId записывается хэндл-айди истекающего таймера
set Caster = LoadUnitHandle( HT, TimerId, 'cstr' ) //В Caster выгружается значение из хэш-таблицы которые мы сохранили под родительским ключем Timer-а (TimerId) и под дочерним ключем 'cstr'
//Ниже в двух функциях LoadReal мы таким же образом выгружаем наши значения из хэш-таблицы но уже под другими дочерними ключами
call GroupEnumUnitsInRange( Group, LoadReal( HT, TimerId, 'cstX' ), LoadReal( HT, TimerId, 'cstY' ), Blizzard_Range, null ) //Выделяет юнитов в области Blizzard_Range (константа равная 300) и их добавление в группу
call ForGroup( Group, function Blizzard_Group ) //Тут происходит вызов действия для группы
call GroupClear( Group ) //Очистка группы от всех юнитов
if GetUnitCurrentOrder( Caster ) != OrderId( "blizzard" ) then //Условие на то что наш герой перестал применять Буран
//if GetUnitCurrentOrder( Caster ) != 0xd0079 then - этот вариант работает быстрее, так как использует id приказа без лишней возни со строками (без OrderId)
call PauseTimer( Timer ) //Остановка таймера (таймер нужно остановить перед удалением так как иногда случается баг что итерация таймера происходит ещё раз)
call DestroyTimer( Timer ) //Удаление таймера
call FlushChildHashtable( HT, TimerId ) //Очистка хэш-таблицы по родительскому ключу (хэндл-айди Timer-а - TimerId)
endif //Конец условия
endfunction //Конец функции
function Blizzard_Actions takes nothing returns nothing //Функция когда герой или юнит применяет способность
if GetSpellAbilityId() == Blizzard_Id then //Условие если способность равна Blizzard_Id (константа равная равкоду Бурана 'A000')
//CTRL + D в редакторе объектов что-бы узнать равкод чего либо
set Timer = CreateTimer() //Создание таймера и его запись в переменную Timer
set TimerId = GetHandleId( Timer ) //Получение хэндл-айди Timer-а и его запись в переменную TimerId
//Сохранения в хэш-таблицу по родительскому ключу TimerId
call SaveUnitHandle( HT, TimerId, 'cstr', GetTriggerUnit() ) //Сохраняется применяющий способность герой или юнит по дочернему ключу 'cstr'
call SaveReal( HT, TimerId, 'cstX', GetSpellTargetX() ) //Сохраняется точка применения способности X по дочернему ключу 'cstX'
call SaveReal( HT, TimerId, 'cstY', GetSpellTargetY() ) //Сохраняется точка применения способности Y по дочернему ключу 'cstY'
call TimerStart( Timer, 1.0, true, function Blizzard_Timer ) //Запуск таймера Timer периодичностью в 1 секунду к которому привязана функция Blizzard_Timer (3 аргумент отвечает за периодичность)
endif //Конец условия
endfunction //Конец функции
function InitTrig_Blizzard takes nothing returns nothing //Функция инициализации триггера (из функции main вызывается InitCustomTriggers() которая вызывает инициализацию всех триггеров на карте)
local trigger t = CreateTrigger() //Создание триггера
local integer i = 0 //Объявление целочисленной переменной
loop //Начало цикла
call TriggerRegisterPlayerUnitEvent( t, Player( i ), EVENT_PLAYER_UNIT_SPELL_EFFECT, null ) //Регистрирует событие применения способности для игрока i (изначально 0, 0 = 1 игрок, и т.д.)
set i = i + 1 //Добавление 1 к i
exitwhen i == bj_MAX_PLAYER_SLOTS //Условие выхода из цикла, тут вместо bj константы должно быть указано макс. кол-во игроков на карте
endloop //Конец цикла
call TriggerAddAction( t, function Blizzard_Actions ) //В триггер добавляется функция с действиями при применения способности
set t = null //Обнуляется локальная переменная
call FogEnable( false ) //Это для видимости на всю карту (удалить)
call FogMaskEnable( false ) //Это для видимости на всю карту (удалить)
endfunction //Конец функции
Ред. LastUchiha
Но ведь вызов функции лишний получится по итогу (я о функции получения хэш-таблицы). И добавить её в шапку карты, верно?
С UnitDamagePoint, оно как то задамажило в первую итерацию таймера, и кастера и его союз (оно не должно дамажить никого кроме врагов), а в след. итерации не захотело дамажить.
Ну как живо, частично да, а так-то хочется онлайн бы поднять.
Ред. LastUchiha
Ред. LastUchiha
Ред. LastUchiha
Ред. LastUchiha
Ред. ScorpioT1000
Ред. Smeto
На 10000 вызовов же, 13ms задержка
Ред. LastUchiha
Ред. nazarpunk
Ужас
Ред. LastUchiha
Ред. nazarpunk
Ред. LastUchiha
Ред. LastUchiha
Ред. LastUchiha
Ред. nazarpunk
Но для новичков нужно учитывать что в таком варианте можно словить коллизию с глобалками. Тут я посоветую грязножасс и использовать приватные глобалки. Но я понимаю что реализация на чистом жассе.
Ред. LastUchiha
Ред. LastUchiha
Ред. nazarpunk
Ред. LastUchiha
Ред. nazarpunk
Ред. nazarpunk