Добавлен , опубликован
Способ реализации:
Версия 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)
15
IzobretatelBoom, имеешь ввиду добавить глобалки прямо в триггер со спеллом в которые добавить константы с параметрами? Хэш-таблицу ведь можно оставить в нестандартном коде? А на сайте всё объединить в коде.
Но ведь вызов функции лишний получится по итогу (я о функции получения хэш-таблицы). И добавить её в шапку карты, верно?
С UnitDamagePoint, оно как то задамажило в первую итерацию таймера, и кастера и его союз (оно не должно дамажить никого кроме врагов), а в след. итерации не захотело дамажить.
Ну как живо, частично да, а так-то хочется онлайн бы поднять.
9
LastUchiha, Да глобалки в начале триггера объявляешь. Функция HASH() просто для удобной интеграции в свою карту. В принципе этого можно не делать, а заставить картоделов самим менять твой H на свой.
15
IzobretatelBoom, ну в основном спелл создан для обучения, кто хочет - может скопировать к себе, но хэш пусть сам меняет, а то ещё будет также функцию такую создавать, хехе. Пусть учатся менять сами! А так онли параметры вынесу в глобалки в триггере со спеллов.
30
Для хеша используй отдельную функцию. В картах, в которых уже есть хеш нужно будет только подставить в функцию переменную своего хеша.
Подставить переменную религия запрещает? Для таблицы, которая хранит данные по хэндлам уже давно прочно устоялось имя HT.
Ответы (2)
15
skydi, ну и что? Какая разница вообще у кого он?) Если спелл создан для того что-бы по нем учится, или к себе на карту копировать.
9
skydi, Кель самый лучший герой для тестов. Самое главное - это герой из TFT, то есть карта сохраняется не в .w3m, а в .w3x. Второе - эстетичность.
15
Вышла новая версия! Прокрутить к ресурсу
  1. Добавлены константы для удобности изменения способности
  2. Добавил глобальные переменные в код в данном ресурсе
30
StringHash( "caster" ) за такое принято отрывать руки и засовывать туда, где не всходит солнце.
Ответы (10)
15
nazarpunk, хех, оно типо медленнее работать будет? Где-то слыхал что операции с string значениями тяжёлые, оно же вроде хэшируется (толи кэшируется, не помню уже) ещё? Тут в целом также можно было объявить StringHash в глобалки под понятные названия. Ну и вообще новичкам думаю со StringHash понятнее будет. Правда я не объяснил что оно делает...
15
nazarpunk, да и мне нравится когда в хэш сохраняется всё в кавычках (визуально для меня хорошо выглядит)
30
LastUchiha, и ты тем же временем боишься заюзать лишнюю integer. Ещё никто не восхищайлся твоей гейниальностью?
15
nazarpunk, да не боюсь я, мне просто не нравится когда что-то некрасиво в коде.
38
nazarpunk, дизлайк, вполне себе строчный ключ, а не твой говнокод из 4 букв, прибитый к языку
30
вполне себе строчный ключ
Напомни мне пожалуйста, когда в варкрафт завезли нормальную работу со строками? Ну а то что он каждый раз вычисляется тебя вообще не смущает?
9
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)
15
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)
15
nazarpunk, почему 3 условия стоят отдельно друг от друга ?
Загруженные файлы
30
LastUchiha, потому что так визуальней удобней смотреть, а не разгребать огромную моностроку. Ну и показать новичкам как можно использовать return в коллбэке.
15
nazarpunk, также, этот момент будет работать быстрее?
Загруженные файлы
30
LastUchiha, этот момент предотвращает создание Condition. Бояться лишней integer и плодить Condition пачками это верх гейниальности.
15
nazarpunk, понял, и почему бы не использовать фильтр как отдельную функцию которая будет проставлена в GroupEnum ? Лишняя функция чи шо ?
30
LastUchiha, а сам Filter ты не учитываешь? Или он не занимает память, которую ты так яросто пытаешься сэкономить?
15
nazarpunk, а это ну для чего ? Ну то есть почему exitwhen выше и i = -1? Лишний раз срабатывает i = i + 1!
Загруженные файлы
9
LastUchiha, Потому что так читать удобней, а не выискивать где конец цикла
15
IzobretatelBoom, ставить exitwhen в самом низу также норм идея. Читается - читается! Ищется - ищется! Не проводиться лишняя итерация цикла - не проводится!
30
Лишний раз срабатывает i = i + 1
Тоесть по твоему инкримент один раз на карту это страшно, а вычиление хэша строки на каждый чих это норм?
15
nazarpunk, ну вот StringHash() - я согласен теперь что не нужно его юзать.
30
я согласен теперь что не нужно его юзать.
А толку от твоего согласия если он до сих пор в исходнике? Можешь кстати тупо мой код взять и под себя переделать. Дарю.
15
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
Плохая практика использовать комбинированый стиль именования.
Ну а в целом все классно, особенно нравится использования глобалок вместо локалок. Кто бы мне в начале пути такое показал...
Но для новичков нужно учитывать что в таком варианте можно словить коллизию с глобалками. Тут я посоветую грязножасс и использовать приватные глобалки. Но я понимаю что реализация на чистом жассе.
15
KaneThaumaturge, при правильном использовании ведь не словить (ну только если действий не особо много)?
20
LastUchiha, ну если юнит умирает от этого бурана и у него при смерти вызывается этот же буран который использует те же глобалки, то можно таймер и кастера потерять после строки нанесения урона. Я не говорю что стоит использовать локалки, просто это нужно учитывать.
20
LastUchiha, ну или например ты ту же глобалку с таймером используешь где-то ещё, и этот код может затриггерится при уроне или смерти. Так что важно разделять области использования при глобалках.
15
KaneThaumaturge, а, ну тут уже зависит от пользователя и того что он хочет реализовать.
30
Плохая практика использовать комбинированый стиль именования.
Здесь нет грязножасса. При наличии триггера Blizzard игра вызовет такую нативку.
20
LastUchiha, ну я это просто пишу для информации. Реализация хорошая.
15
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
просто иногда тебе важно чтобы это исполнилось в одном "потоке"
Просто иногда тебе лень спроэктировать систему, в которой это не важно. Ну или перейти на ас, где всё живет в своём инстансе и вообще до одного места на перезапись глобалок.
8
Вот тут Назарчик во всей красе смотрится, обзор на код весьма занимательный.
Ответы (2)
25
nazarpunk, своя реализация рошной заливки архимага что ли? Так можно так и написать
15
Вышла новая версия! Прокрутить к ресурсу
Переписал весь спелл (с помощью от 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() //Создаём группу, которую будем использовать для моментальной выборки юнитов
15
nazarpunk, так а про итерацию, вынести к комментам в начале триггера?
30
так а про итерацию, вынести к комментам в начале триггера?
Ну да. В блоке удаления это явно не к месту.
30
Как я понял, ты просто взял дефолт буран и добавил к нему урона. А будет версия с рандомными эффектами?
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.