Добавлен , опубликован
Способ реализации:
Версия Warcraft:
Простое заклинание для новичков. Добавляет к стандартному Бурану дополнительный 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 //Конец функции

Требования

Скопировать код из шапки карты и триггера со спеллом к себе на карту, если такие глобальные переменные уже имеются, то копировать не надо. Поменять равкод способности в константах если он другой (скорее всего другой).
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
9
  1. Добавь объявление глобалок
globals
    constant integer ABILITY_BLIZZARD = 'A000' //Способность (используется в условии)
    hashtable H = InitHashtable()
	...
endglobals
  1. Для хеша используй отдельную функцию. В картах, в которых уже есть хеш нужно будет только подставить в функцию переменную своего хеша.
function HASH takes nothing returns hashtable
    return udg_HASH
endfunction
  1. Для нанесения урона по области используй функцию UnitDamagePoint или гуи функцию UnitDamagePointLoc "Приказать юниту атаковать область". В UnitDamagePoint куча страшных непонятных аргументов, я сам в них не разбераюсь, поэтому рекомендую второй вариант.
  1. 3 пункт в начале кода некорректен, нельзя воскресить то что и так живо.
Оценка: 51 комментариев из 48 строчек кода. Лайк
Ответы (4)
16
IzobretatelBoom, имеешь ввиду добавить глобалки прямо в триггер со спеллом в которые добавить константы с параметрами? Хэш-таблицу ведь можно оставить в нестандартном коде? А на сайте всё объединить в коде.
Но ведь вызов функции лишний получится по итогу (я о функции получения хэш-таблицы). И добавить её в шапку карты, верно?
С UnitDamagePoint, оно как то задамажило в первую итерацию таймера, и кастера и его союз (оно не должно дамажить никого кроме врагов), а в след. итерации не захотело дамажить.
Ну как живо, частично да, а так-то хочется онлайн бы поднять.
9
LastUchiha, Да глобалки в начале триггера объявляешь. Функция HASH() просто для удобной интеграции в свою карту. В принципе этого можно не делать, а заставить картоделов самим менять твой H на свой.
16
IzobretatelBoom, ну в основном спелл создан для обучения, кто хочет - может скопировать к себе, но хэш пусть сам меняет, а то ещё будет также функцию такую создавать, хехе. Пусть учатся менять сами! А так онли параметры вынесу в глобалки в триггере со спеллов.
30
Для хеша используй отдельную функцию. В картах, в которых уже есть хеш нужно будет только подставить в функцию переменную своего хеша.
Подставить переменную религия запрещает? Для таблицы, которая хранит данные по хэндлам уже давно прочно устоялось имя HT.
Ответы (2)
16
skydi, ну и что? Какая разница вообще у кого он?) Если спелл создан для того что-бы по нем учится, или к себе на карту копировать.
9
skydi, Кель самый лучший герой для тестов. Самое главное - это герой из TFT, то есть карта сохраняется не в .w3m, а в .w3x. Второе - эстетичность.
16
Вышла новая версия! Прокрутить к ресурсу
  1. Добавлены константы для удобности изменения способности
  2. Добавил глобальные переменные в код в данном ресурсе
30
StringHash( "caster" ) за такое принято отрывать руки и засовывать туда, где не всходит солнце.
Ответы (10)
16
nazarpunk, хех, оно типо медленнее работать будет? Где-то слыхал что операции с string значениями тяжёлые, оно же вроде хэшируется (толи кэшируется, не помню уже) ещё? Тут в целом также можно было объявить StringHash в глобалки под понятные названия. Ну и вообще новичкам думаю со StringHash понятнее будет. Правда я не объяснил что оно делает...
16
nazarpunk, да и мне нравится когда в хэш сохраняется всё в кавычках (визуально для меня хорошо выглядит)
30
LastUchiha, и ты тем же временем боишься заюзать лишнюю integer. Ещё никто не восхищайлся твоей гейниальностью?
16
nazarpunk, да не боюсь я, мне просто не нравится когда что-то некрасиво в коде.
38
nazarpunk, дизлайк, вполне себе строчный ключ, а не твой говнокод из 4 букв, прибитый к языку
30
вполне себе строчный ключ
Напомни мне пожалуйста, когда в варкрафт завезли нормальную работу со строками? Ну а то что он каждый раз вычисляется тебя вообще не смущает?
10
nazarpunk, А где у нас разница будет ощутима?
На 10000 вызовов же, 13ms задержка
A
const integer CasterKEY = StringHash( "caster" )
и во все до 7ms уменьшает задержку против твоих рекомендованных 6ms
38
nazarpunk, да пусть вычисляется, это считанные такты. Константные строки лежат себе в памяти и никуда не дублируются
Учите херне какой-то, код ради кода
Где прорывные разработки, где демки, где стиль. Одни таймеры и инкомы
30
Ужас. Три вызова функции GetFilterUnit и почему UnitAlive не в самом начале?
function Blizzard_Filter takes nothing returns boolean //функция фильтра (фильтруются юниты, в группе юнитов остаются только враги)
    return IsUnitEnemy( GetFilterUnit(), GetOwningPlayer( uTemp ) ) and not IsUnitType( GetFilterUnit(), UNIT_TYPE_STRUCTURE ) and UnitAlive( GetFilterUnit() ) //сам фильтр       
endfunction 
Ответы (4)
16
nazarpunk, да с UnitAlive согласен, не в том порядке поставил. Три вызова функции - а спроси почему я не захотел сделать глобалку под FilterUnit, сам не знаю ответ на этот вопрос)
30
сам не знаю ответ на этот вопрос)
Я знаю, но за такое на сайте варны дают.
30
Рецензия на публикацию

Ужас

Если код подразумевается как обучение новичков, то автора необходимо расстрелять за вредительство. Вместо тысячи слов я его переписал по человечески.
native UnitAlive takes unit id returns boolean

globals
	hashtable HT = InitHashtable()
	group Group = CreateGroup()

	unit Caster
	real CasterX
	real CasterY

	unit Target

	timer Timer
	integer TimerId

	constant integer SpellBlizzardId = 'A000'
	constant real SpellBlizzardRange = 300
	constant real SpellBlizzardDamage = 300
endglobals

function SpellBlizzardEnum takes nothing returns nothing
	set Target = GetEnumUnit()
	if not UnitAlive(Target) then 
		return 
	endif
	if not IsUnitEnemy(Target, GetOwningPlayer(Caster)) then 
		return 
	endif
	if IsUnitType(Target, UNIT_TYPE_STRUCTURE) then
		return 
	endif

	call UnitDamageTarget(Caster, Target, SpellBlizzardDamage, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_UNKNOWN, WEAPON_TYPE_WHOKNOWS) 
endfunction 

function SpellBlizzardCallback takes nothing returns nothing
	set Timer = GetExpiredTimer()
	set TimerId = GetHandleId(Timer)
    
	set Caster = LoadUnitHandle(HT, TimerId, 'cstr')
	set CasterX = LoadReal(HT, TimerId, 'cstX')
	set CasterY = LoadReal(HT, TimerId, 'cstY')

	call GroupEnumUnitsInRange(Group, CasterX, CasterY, SpellBlizzardRange, null)
	call ForGroup(Group, function SpellBlizzardEnum) 
	call GroupClear(Group)
    
	if GetUnitCurrentOrder(Caster) != 0xd0079 then // blizzard
		call PauseTimer(Timer)
		call DestroyTimer(Timer)
		call FlushChildHashtable(HT, TimerId)
	endif 
endfunction 

function SpellBlizzardAction takes nothing returns nothing 
	if GetSpellAbilityId() != SpellBlizzardId then
		return
	endif
	set Caster = GetTriggerUnit()
	set CasterX = GetSpellTargetX()
	set CasterY = GetSpellTargetY()
	set Timer = CreateTimer() 
	set TimerId = GetHandleId(Timer)
    
	call SaveUnitHandle(HT, TimerId, 'cstr', Caster)
	call SaveReal(HT, TimerId, 'cstX', CasterX)
	call SaveReal(HT, TimerId, 'cstY', CasterY)
	call TimerStart(TimerId, 1.0, true, function SpellBlizzardCallback) 
endfunction

function InitTrig_Blizzard takes nothing returns nothing
	local trigger t = CreateTrigger()
	local integer i = -1

	loop
		set i = i + 1
		exitwhen i == bj_MAX_PLAYER_SLOTS
		call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null) //регистрирует событие применения способности для игрока i (изначально 0, 0 = 1 игрок, и так далее по порядку)
	endloop
    
	call TriggerAddAction(t, function SpellBlizzardAction) 
	set t = null
endfunction

P.S. Сюда бы по хорошему добавить уровней абилки и правильную работу с расстоянием до юнита, но в рамках пособия и так сойдёт.
Ответы (44)
16
nazarpunk, почему 3 условия стоят отдельно друг от друга ?
Загруженные файлы
30
LastUchiha, потому что так визуальней удобней смотреть, а не разгребать огромную моностроку. Ну и показать новичкам как можно использовать return в коллбэке.
16
nazarpunk, также, этот момент будет работать быстрее?
Загруженные файлы
30
LastUchiha, этот момент предотвращает создание Condition. Бояться лишней integer и плодить Condition пачками это верх гейниальности.
16
nazarpunk, понял, и почему бы не использовать фильтр как отдельную функцию которая будет проставлена в GroupEnum ? Лишняя функция чи шо ?
30
LastUchiha, а сам Filter ты не учитываешь? Или он не занимает память, которую ты так яросто пытаешься сэкономить?
16
nazarpunk, а это ну для чего ? Ну то есть почему exitwhen выше и i = -1? Лишний раз срабатывает i = i + 1!
Загруженные файлы
9
LastUchiha, Потому что так читать удобней, а не выискивать где конец цикла
16
IzobretatelBoom, ставить exitwhen в самом низу также норм идея. Читается - читается! Ищется - ищется! Не проводиться лишняя итерация цикла - не проводится!
30
Лишний раз срабатывает i = i + 1
Тоесть по твоему инкримент один раз на карту это страшно, а вычиление хэша строки на каждый чих это норм?
16
nazarpunk, ну вот StringHash() - я согласен теперь что не нужно его юзать.
30
я согласен теперь что не нужно его юзать.
А толку от твоего согласия если он до сих пор в исходнике? Можешь кстати тупо мой код взять и под себя переделать. Дарю.
16
nazarpunk, вот, сделал всё максимально близко к твоему способу за исключением нескольких моментов:
  1. exitwhen внизу
  2. в функции каста в проверку на способность сразу вставил код вместо return
  3. не записываю в функции каста координаты каста в переменные CastX, CastY, а сразу записываю в хэш-таблицу
  4. с выгрузкой координат каста также, не записываю в переменные, а сразу выгружаю в GroupEnum
  5. OrderId( "blizzard" ) оставил для ясности (если бы код выходил за рамки пособия - то пожалуйста)
  6. все 3 if-а собрал в один if, имхо это правильный вариант (моя задача показать новичкам как правильно сделать, а не как улучшить читаемость кода до небес), насчёт читаемости безспорно твой вариант лучше.
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 = 300
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
    set Timer = GetExpiredTimer()
    set TimerId = GetHandleId( Timer )
    set Caster = LoadUnitHandle( HT, TimerId, 'cstr' )
    
    call GroupEnumUnitsInRange( Group, LoadReal( HT, TimerId, 'cstX' ), LoadReal( HT, TimerId, 'cstY' ), Blizzard_Range, null )
    call ForGroup( Group, function Blizzard_Group )
    call GroupClear( Group )

    if GetUnitCurrentOrder( Caster ) != OrderId( "blizzard" ) then
        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 TimerStart( Timer, 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
endfunction
30
LastUchiha,
  1. Вкусовщина
  2. Вкусовщина
  3. Вкусовщина
  4. Вкусовщина
  5. Здесь важно. Напиши ниже вариант с числом и закомментируй его.
  6. Вкусовщина. И в жассе мой способ не сильно повышает читаемость. Ибо строки плодит. Вот в ангеле и Зинке там была бы одна строка и Мега читаемость.
20
nazarpunk,
InitTrig_Blizzard
Плохая практика использовать комбинированый стиль именования.
Ну а в целом все классно, особенно нравится использования глобалок вместо локалок. Кто бы мне в начале пути такое показал...
Но для новичков нужно учитывать что в таком варианте можно словить коллизию с глобалками. Тут я посоветую грязножасс и использовать приватные глобалки. Но я понимаю что реализация на чистом жассе.
16
KaneThaumaturge, при правильном использовании ведь не словить (ну только если действий не особо много)?
20
LastUchiha, ну если юнит умирает от этого бурана и у него при смерти вызывается этот же буран который использует те же глобалки, то можно таймер и кастера потерять после строки нанесения урона. Я не говорю что стоит использовать локалки, просто это нужно учитывать.
20
LastUchiha, ну или например ты ту же глобалку с таймером используешь где-то ещё, и этот код может затриггерится при уроне или смерти. Так что важно разделять области использования при глобалках.
16
KaneThaumaturge, а, ну тут уже зависит от пользователя и того что он хочет реализовать.
30
Плохая практика использовать комбинированый стиль именования.
Здесь нет грязножасса. При наличии триггера Blizzard игра вызовет такую нативку.
20
LastUchiha, ну я это просто пишу для информации. Реализация хорошая.
16
KaneThaumaturge, я понял, у меня уже был случай перезаписи, но там в кастомной функции перезаписывало)
30
то можно таймер и кастера потерять после строки нанесения урона.
Посмотрел я после строки нанесения урона, как жаль, там столько использования этих переменных...
20
nazarpunk, не понял сарказм, а этот код шутка? Или это я что-то не понял?
call GroupClear(Group)
    
	if GetUnitCurrentOrder(Caster) != 0xd0079 then // blizzard
		call PauseTimer(Timer)
		call DestroyTimer(Timer)
		call FlushChildHashtable(HT, TimerId)
	endif 
30
ну или например ты ту же глобалку с таймером используешь где-то ещё, и этот код может затриггерится при уроне или смерти.
Может. Но всегда же можно вручную переменные заприватить. Благо уже даже плагины для этого есть.
30
не понял сарказм, а этот код шутка?
Это простая и эллегантная проверка на какст channel. Что не так то?
20
nazarpunk, не я про то, что в этом коде коллизия может быть с глобалками потому что он исполняется после нанесения урона
30
не я про то, что в этом коде коллизия может быть с глобалками потому что он исполняется после нанесения урона
Именно в этом не может. Потому что после урона нет работы с глобалками и тик таймера завершается. А следующий тик таймера перепишет глобалки заново.
Стопе, забыл. Чтоб точно не было коллизий нужно урон в самый низ отправить:
function SpellBlizzardCallback takes nothing returns nothing
	set Timer = GetExpiredTimer()
	set TimerId = GetHandleId(Timer)
    
	set Caster = LoadUnitHandle(HT, TimerId, 'cstr')

	if GetUnitCurrentOrder(Caster) != 0xd0079 then // blizzard
		call PauseTimer(Timer)
		call DestroyTimer(Timer)
		call FlushChildHashtable(HT, TimerId)
       return
	endif 

	set CasterX = LoadReal(HT, TimerId, 'cstX')
	set CasterY = LoadReal(HT, TimerId, 'cstY')

	call GroupEnumUnitsInRange(Group, CasterX, CasterY, SpellBlizzardRange, null)
	call ForGroup(Group, function SpellBlizzardEnum) 
	call GroupClear(Group)    
endfunction 
20
nazarpunk, именно в этом не может быть, да. Я же говорю, это так для информации. Если этот код модифицировать и использовать с ивентом урона, то может быть.
30
KaneThaumaturge, можно вообще решить этот вопрос эллегантно - создать DamageDeal систему с 0.1 таймером. Которая будет отложенно наносить урон.
Но здесь уже мы ступаем в область архитектуры.
20
nazarpunk, достаточно задержку в 0 на таймере, проверено. Я так и делаю. Только у меня модификаторы урона моментально срабатывают, а ивент на сам урон с задержкой.
20
nazarpunk, в целом лучше просто фор груп прям в конец переместить. Мб так лучше будет
30
в целом лучше просто фор груп прям в конец переместить. Мб так лучше будет
Ты забыл что ForGroup наносит поочерёдно урон? На втором юните всё сломается. А вот урон с задержкой решит проблему в корне. И можно будет перемещать как угодно. Тригер уже отработает и на переменные будет глубоко.
30
Только у меня модификаторы урона моментально срабатывают, а ивент на сам урон с задержкой.
Так это уже рюшечки. Главное базис сохранить - вызывать всё, что может стригерить событие с задержкой. Тогда можно во всю обмазаться универсальными глобалками и капитально сократить количество лишнего кода.
20
nazarpunk, а чё сломается, если ты форгруп запустишь и удалишь группу, то он все равно отработает
20
nazarpunk, да, я раньше брезговал задержку в 0 ставить. Но мне кажется это прям классная штука сейчас. Мб везде так сделаю.
20
KaneThaumaturge,
форгруп запустишь и удалишь группу, то он все равно отработает
Я вроде тестил такое, хотя уже не уверен.
20
nazarpunk, просто иногда тебе важно чтобы это исполнилось в одном "потоке"
30
просто иногда тебе важно чтобы это исполнилось в одном "потоке"
Просто иногда тебе лень спроэктировать систему, в которой это не важно. Ну или перейти на ас, где всё живет в своём инстансе и вообще до одного места на перезапись глобалок.
10
Вот тут Назарчик во всей красе смотрится, обзор на код весьма занимательный.
Ответы (2)
26
nazarpunk, своя реализация рошной заливки архимага что ли? Так можно так и написать
16
Вышла новая версия! Прокрутить к ресурсу
Переписал весь спелл (с помощью от nazarpunk)
Ответы (3)
30
LastUchiha, годнота. Лайк. Только формулировка сбивает с толку:
это результат конвертации строки "blizzard" в целочисленное значение
Это не конвертация, это настоящий ид приказа. Строки сбоку присраны для гуймуйщмков.
30
LastUchiha, у приказове есть целлочисленный id, который и использует игра. А есть представление в виде строки, которое используется в РО и гуймуй чтоб кожанным мешкам было удобней.
//if GetUnitCurrentOrder( Caster ) != 0xd0079 then - этот вариант работает быстрее, так как использует ид приказа без лишней возни со строками
30
Итерация (повторение) - повторение таймера или цикла (тут таймер повторяется раз в 1 секунду, то есть раз в 1 секунду происходит итерация таймера)
Этот коммент вообще не в том месте находится.

Когда копипастил забыл вкомментариях изменить ключи:
call SaveReal( HT, TimerId, 'cstX', GetSpellTargetX() ) //Сохраняется точка применения способности X по дочернему ключу 'cstr'
call SaveReal( HT, TimerId, 'cstY', GetSpellTargetY() ) //Сохраняется точка применения способности Y по дочернему ключу 'cstr'

group Group = CreateGroup() //Создаёт темповая группа
Это не темповая (слово "временна" видать запретили), а глобальная группа, которая используется для всех одноразовых переборов GroupEnum*.
Ответы (4)
30
group Group = CreateGroup() //Создаём группу, которую будем использовать для моментальной выборки юнитов
16
nazarpunk, так а про итерацию, вынести к комментам в начале триггера?
30
так а про итерацию, вынести к комментам в начале триггера?
Ну да. В блоке удаления это явно не к месту.
30
Как я понял, ты просто взял дефолт буран и добавил к нему урона. А будет версия с рандомными эффектами?
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.