Складывается только благословение элуны или дефенд - фактор урона от магии - 1 это 100% урона, 0.70 это 70% урона , т.е из 100 прошло только 70 урона, 30 заблокировалось.
Тут восстанавливать нечего, вся карта состоит из нулей, т.е её стер редактор на диске собрался из оперативки записать заного да неуспел, гг. Ищи в папке с JNGP бекапы, он автоматом сохраняет бекап после каждого сохранения карты в редакторе.
Parom_Harona, Пауз + перемещение таймером исходя из требуемой скорости, хочешь скорость 900 делишь на период (32 раза в сек к примеру, 0.03125) получится 28.125 ну вот и двигаешь юнита к цели по 28 ед каждый тик таймера, так же проверяешь что цель сдохла или летун сдохли.
Можно и на мемхаке с кастомным станом, но ты явно недорос..
Все кампании на гуях, на Ии и прочем счастье 2002 года, они будут делать не отлтчимо от того что было в плане кода, что все кампании на луахи перепишут? Ненадежно, индус ошибается и бага по средь презентации перед выпуском на рынок =)
Щяс выяснится что Reforged вовсе без редактора постановляется, и будет редактор не пойми когда...
Потом непонятно куда и зачем будут двигаться близзарды и почему именно ЛУА? Они в jasm машине то ноги переломали, а им тут надо будет пилить новый пепелац и заставить его понимать старые карты из кампании или править и копипастить весь JASS API + синтаксис чтобы работало нормально.
ну в теории это могут делать только войска альянса, при условии что они союзники. Здание всеравно будет пренадлежать тому кто его начал строить, так же можно триггерно менять владельцев здания, снять зданию при начале постройки немного хп - чтобы его мог чинить рабочий союзника, а при приказе чинить меняем владельца здания и достраиваем.
Реализация с помощью рун куда проще в реализации дамми каста, практически не требует кода и не плодит утечек, если делать все как в моей статье, там есть примеры для гуишников. Так же руны куда меньше нагружают движок, т.к весят меньше юнитов, это может быть полезно в случаях где нужно создавать очень много даммиков кастующих что либо...
Ах да, с помощью рун изи сделать и чаннелинг спелла не чаннелинг вроде дождя., или землетрясения с прочей.
function GetEvasionOrderIdFunctionData takes nothing returns nothing
local integer oldprotection
local integer a
call UnitAddAbility( DummyAttacker,'AEev' )
set a = GetUnitAbility(DummyAttacker,'AEev' )
if ( a > 0 ) then
set pEvasionOrderIdFunction=RMem( RMem( a ) +0x30C )
if pEvasionOrderIdFunction > GameDLL then
call UnitAddAbility( DummyAttacker, 'Aesn' )
set a=GetUnitAbility(DummyAttacker, 'Aesn')
if ( a > 0 ) then
set a=RMem(a)+0x30C
set oldprotection=ChangeOffsetProtection(a,4,0x40)
call WMem( a,pEvasionOrderIdFunction )
call ChangeOffsetProtection( a,4,oldprotection )
endif
call UnitRemoveAbility( DummyAttacker, 'Aesn' )
endif
else
//port value from AEev to Afla to disable icons
endif
call UnitRemoveAbility(DummyAttacker,'AEev')
endfunction
Вот для пассивок, при изучении вызвать call FixChargesIndicator( юнит, ид абилки )
Далее сохраняем для скорости адресс куда-нибудь и юзаем call SetAbilityChargesByAddr( адресс, заряды )
Эмм а заклинания более подходящего не нашлось? У огненно дождя есть настройка отвечающая за периодический урон целям, задетых врагов будет жечь огонь. Чтобы ненужно было указывать цель - делаем руну, если её подберет герой над ним пойдет огненный дождь, кол-во волн, анимацию, урон и цели можно настроить по вкусу.
Что в твоем понимании "стандартная инициализация"? Если что в редакторе карт у тебя нет заботы о об этом, все триггеры созданые в редакторе триггеров автоматически будут инициализированы вызовом из функции InitCustomTriggers(), редактор сам генерирует InitCustomTriggers() и добавляет туда вызовы всех InitTrig_функций, оптимизаторы сливают в функцию main сразу содержимое InitCuntomTriggers и InitTrig функций.
Тебе один путь - добавлять в маин свои триггеры, если там как говна гуи и начинается обрыв потока при лимите операций - таймер который через 0.00 сек будет запускать функцию для инициализации всех твоих триггеров.
Так же норм люди уже давно не плодят по каждому триггеру на 1 спелл, а юзают 1 триггер для всех спеллов сразу, в разы уменьшается кол-во кода а так же число лишних телодвижений.
Интересно зачем все это, регены и так вычисляются вектроно а не ровно N в сек, чем выше хп реген тем чаще добавляется здоровье - неверите, вручите ауру смерти с % регенерации 1х и попробуйте подраться с нейтралами, в итоге вы увидите что хп у вас вовсе не отнимается.
Для триггерного регена достаточно одного таймера в 0.25 сек, и добавлять юниту хп. Реализация достаточно простая, группа юнитов + запись в кастом-вал кол-во хп в сек, при смерти или каком-нить вредном эффекта удаляем юнита из группы, а при создании или возрождение добавляем снова.
Тут скорее всего еще проблема с кодом карты, деоптимизаторы не восстанавливают данные на 100% и ошибки будут почти всегда, 100% рабочий способ - создавать объекты с нуля в карте руками, с теми же id и параметрами что в карте которую вы хотели восстановить...
Ну это счетчик срабатывания триггера, иногда в динамических триггерах юзается в качестве заменителя еще 1 переменной, к примеру тебе нужно двигать юнита на расстояние N и прекратить его двигать когда он сдохнет или когда-триггер сработает N раз, активно юзается в доте фрога. Можно найти и другое применение.
Как сделать - очень просто, это классический спел по типу волна, представляет из себя векторное движение дамми юнита с помощью таймера, примеры есть в статьях и наработках. Вычисляешь угол между применившим заклинание и точкой применения заклинния, если в качестве цели указан юнит, то угол ищем между применившим и целью, создаем даммика и с помощью таймера в 0.03125 (32 раза в сек более чем достаточно) двигаем дамми юнита в ранее найденном нами направлении, по истечению определенного кол-ва тиков таймера, ну 32х30 это примерно 0.9 секунды и 960 ед расстояния (если двигать цель по 30 ед. за каждый тик), ну так же если нужно наносить урон врагам, для этого используются две группы и фильтр.
Пример кода
function Group_Frost_Wave_Actions takes nothing returns nothing
local DamageData dd = bj_forLoopAIndexEnd
local unit Enemy = GetEnumUnit( )
call GroupAddUnit( dd.grp, Enemy )
set bj_lastCreatedUnit = CreateUnit( Player( PLAYER_NEUTRAL_PASSIVE ), 'hatk', GetUnitX( Enemy ), GetUnitY( Enemy ), GetUnitFacing( Enemy ) )
call SetUnitPathing( bj_lastCreatedUnit, false )
call UnitApplyTimedLife( bj_lastCreatedUnit, 'BTLF', 0.50 )
call UnitAddAbility( bj_lastCreatedUnit, 'A06Z' )
call SetUnitAbilityLevel( bj_lastCreatedUnit, 'A06Z', dd.id )
call SetUnitX( bj_lastCreatedUnit, GetUnitX( Enemy ) )
call SetUnitY( bj_lastCreatedUnit, GetUnitY( Enemy ) )
if IssueTargetOrderById( bj_lastCreatedUnit, 852243, Enemy ) then
call UnitDamageTarget( dd.attacker, Enemy, dd.dmg, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS )
call DestroyEffect( AddSpecialEffectTarget( "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl", Enemy, "origin" ) )
endif
set bj_lastCreatedUnit = null
set Enemy = null
endfunction
function Timer_Frost_Wave_Expires takes nothing returns nothing
local timer t = GetExpiredTimer( )
local DamageData dd = GetDataBX( t )
set dd.time = dd.time + 1
if dd.time > 25 then //25 * 32 = 800
call DestroyEffect( dd.fx )
call KillUnit( dd.attacked )
call GroupClear( dd.grp )
call ReleaseGroup( dd.grp )
call PauseTimer( t )
call RemoveDataBX( t )
call DestroyTimer( t )
call dd.clear( )
call dd.destroy( )
else
set dd.rx = dd.rx + 32.00 * Cos( dd.hp )
set dd.ry = dd.ry + 32.00 * Sin( dd.hp )
call SetUnitX( dd.attacked, CheckX( dd.rx ) )
call SetUnitY( dd.attacked, CheckY( dd.ry ) )
call GroupClear( gg_grp_TempGroup )
set bj_groupEnumOwningPlayer = dd.pl
set bj_forLoopAIndexEnd = dd
set bj_lastReplacedUnit = dd.attacker
call GroupEnumUnitsInRange( gg_grp_TempGroup, dd.rx, dd.ry, 128.00 + 4.00 * dd.time, OnlyWavedEnemy )
call ForGroup( gg_grp_TempGroup, function Group_Frost_Wave_Actions )
set bj_lastReplacedUnit = null
endif
set t = null
endfunction
//===========================================================================
function startTrig_Frost_Wave takes nothing returns nothing
local timer t = CreateTimer( )
local DamageData dd = DamageData.create( )
set dd.attacker = GetSpellAbilityUnit( )
set dd.id = GetUnitAbilityLevel( dd.attacker, 'A060' )
set dd.dmg = dd.id * 125.00
set dd.pl = GetOwningPlayer( dd.attacker )
set dd.hp = Atan2( GetSpellTargetY( ) - GetUnitY( dd.attacker ), GetSpellTargetX( ) - GetUnitX( dd.attacker ) )
set dd.rx = GetUnitX( dd.attacker ) + 32.00 * Cos( dd.hp )
set dd.ry = GetUnitY( dd.attacker ) + 32.00 * Sin( dd.hp )
set dd.attacked = CreateUnit( dd.pl, 'hdum', dd.rx, dd.ry, bj_RADTODEG * dd.hp )
set dd.fx = AddSpecialEffectTarget( "Abilities\\Spells\\Other\\WindWave\\PrismaticWave.mdx", dd.attacked, "origin" )
set dd.grp = NewGroup( )
set dd.time = 0
call SetDataBX( t, dd )
call SetUnitFlyHeight( dd.attacked, 0.00, 0.00 )
call SetUnitScale( dd.attacked, 1.25, 1.25, 1.25 )
call TimerStart( t, 0.03125, true, function Timer_Frost_Wave_Expires )
set t = null
endfunction
Вот так выглядит аналог того что на твоих картинках в коде, кода минимум, да и ничего заумного нет.
PT153, ну я пока ниче не делал, пока обдумываю че к чему, т.к довольно много кода копипастить и переделывать нехотелось бы, если интересна подробная реализация в моей карте текущей системы - могу скинуть .
PT153, насчет станов и почему негодится таймер - когда мы вешаем на юнита стан с помощью мемхака мы обязаны убедится что он жив и не сдохнет, прежде чем мы снимем с него оглушение, иначе начнется трешь и угар. В краце - есть событие - виджет помер, оно же и юзается стандартными бафами чтобы снять свой эффект ровно на фрейм раньше того как юнит реально умрет, это важно для многих эффектов, даже смерть с крестом перерождения снимает все баффы с цели (от дефолтных абилок варкравта).
Есть другие вещи - псевдоконтроль, помните мою статью про руны и как сделать дуель легион команнедра, в от личии от всяких пауз, скрытия карт команд и прочего говна которое городят картоделы, реализация с помощью мемхака выше не на одну голову. Т.к работает по механике стандартных дизейблов варкрафта, т.е карта команд не скрывается, вы неможите управлять юнитов но его очередь приказов не сбивается и приказы добавленные во время дизейбла будут выполнены после его окончания, если это конечно возможно, это чертовски удобно и правильно. Вспомните доту айсфрога, герой Axe заставляет атаковать себя с помощью одной абилки а при ваших приказах атаки у него прокает пассивка хотите вы в него зарядить спелл чтобы отталкнуть его от себя или застанить а неможите, его агр таймер который тупо приказывает атаковать его много раз в сек, когда агр закончится - вы стоите и ниче не делайте, нужно отдавать приказ чето делать, а жмакать кнопки во время агра себе дороже - чаще прокает пассивка!
Мемхаком же возможно сделать все похожие способности по человечески, выдаем флаг стана и следим за то что юнит получил приказ цель-обьект, юнит умер, время вышло, спелл рассеяли. Приказ нужно ослеживать обязательно, иначе на юнита под флагом стана перестанут действовать станы и все что основано на оглушении (все стандартные дизейблы не дающие двигаться + триггерная пауза), поэтому нам нужно узнать что юниту суют приказ стана, тут же убрать флаг стана, тогда стандартный дизейбл на него подействует и он будет в нем до его окончания, а как отследить его конец ! - правильно, по урону в 0 ед. и текущему приказу, триггер еще и урон должен отслеживать, какая туча событий на 1 юнита. Тут именнно и нужны динамические триггеры а таймеры не подходят по ряду причин.
Надеюсь я объяснил почему именно триггеры, поверь отравление наносящие только урон или какую-нибудь фрост нову я на триггерах бы не делал.
NazarPunk, идея сделать это удобно и гибко, а то что это можно сделать с помощью цикла + хт или структур я знаю.
Про unit indexer что такое?
Я думал о примерно таком коде:
код
struct BuffData
trigger array buffs[50]
boolean array flags[50]
integer count
method Dispel takes boolean flag returns boolean
local integer nIndex = 1
if flag then
loop
exitwhen nIndex > this.count
call TriggerExecute( this.buffs[nIndex] )
set nIndex = nIndex + 1
endloop
else
loop
exitwhen nIndex > .count
if not this.flags[nIndex] then
call TriggerExecute( this.buffs[nIndex] )
endif
set nIndex = nIndex + 1
endloop
endif
return true
endmethod
method AddBuff takes trigger trg, boolean flag returns boolean
set this.count = this.count + 1
if this.count > 50 then
return false
endif
set this.buffs[this.count] = trg
set this.flags[this.count] = flag
return true
endmethod
method RemoveBuff takes trigger trg returns boolean
local integer nIndex = 1
local boolean NotFound = true
loop
exitwhen nIndex > this.count
if trg == this.buffs[nIndex] then
set this.buffs[nIndex] = null
set this.flags[nIndex] = false
set NotFound = false
exitwhen true
endif
set nIndex = nIndex + 1
endloop
if NotFound then
return false
endif
loop
exitwhen nIndex > this.count
set this.buffs[nIndex] = this.buffs[nIndex+1]
set this.flags[nIndex] = this.flags[nIndex+1]
set nIndex = nIndex + 1
endloop
set this.count = this.count - 1
return true
endmethod
endstruct
Пока банальное ветвление ифами, ибо сначала было таких триггеров немного и я не заваривался над реализацией.
» WarCraft 3 / Что лучше для сопротивления магии
» WarCraft 3 / Как сделать эволюцию юнита на убийствах на триггерах
» WarCraft 3 / Отлично, у меня сломалась карта.
» WarCraft 3 / Прохождение юнита сквозь все.
Можно и на мемхаке с кастомным станом, но ты явно недорос..
» WarCraft 3 / Прохождение юнита сквозь все.
Как сделан блинкстрайк рики можешь посмотреть в опен доте.
» WarCraft 3 / Lua
» WarCraft 3 / Дота, редактор и триггеры
» WarCraft 3 / Lua
Потом непонятно куда и зачем будут двигаться близзарды и почему именно ЛУА? Они в jasm машине то ноги переломали, а им тут надо будет пилить новый пепелац и заставить его понимать старые карты из кампании или править и копипастить весь JASS API + синтаксис чтобы работало нормально.
» WarCraft 3 / Командная постройка
» WarCraft 3 / Свиток регенерации с отрицательным восстановлением
Ах да, с помощью рун изи сделать и чаннелинг спелла не чаннелинг вроде дождя., или землетрясения с прочей.
» WarCraft 3 / Ещё раз про заряды способностей на мемхаке, не получается
Далее сохраняем для скорости адресс куда-нибудь и юзаем call SetAbilityChargesByAddr( адресс, заряды )
» WarCraft 3 / Свиток регенерации с отрицательным восстановлением
» WarCraft 3 / Реально вернуть инициализацию в нормальный вид
Тебе один путь - добавлять в маин свои триггеры, если там как говна гуи и начинается обрыв потока при лимите операций - таймер который через 0.00 сек будет запускать функцию для инициализации всех твоих триггеров.
Так же норм люди уже давно не плодят по каждому триггеру на 1 спелл, а юзают 1 триггер для всех спеллов сразу, в разы уменьшается кол-во кода а так же число лишних телодвижений.
» WarCraft 3 / Частота смены показателей здоровья и маны
Для триггерного регена достаточно одного таймера в 0.25 сек, и добавлять юниту хп. Реализация достаточно простая, группа юнитов + запись в кастом-вал кол-во хп в сек, при смерти или каком-нить вредном эффекта удаляем юнита из группы, а при создании или возрождение добавляем снова.
» WarCraft 3 / После слк оптимизации ошибка
» XGM Конкурсы / Warcraft III Mini-Game Contest-2018
» WarCraft 3 / missing return
» WarCraft 3 / Слишком агрессивные крипы
» WarCraft 3 / Функция ResetTrigger()
» WarCraft 3 / Движение, jass
» WarCraft 3 / Динамический триггер ?!
» WarCraft 3 / Динамический триггер ?!
» WarCraft 3 / Аттач группы триггеров
» WarCraft 3 / Аттач группы триггеров
Есть другие вещи - псевдоконтроль, помните мою статью про руны и как сделать дуель легион команнедра, в от личии от всяких пауз, скрытия карт команд и прочего говна которое городят картоделы, реализация с помощью мемхака выше не на одну голову. Т.к работает по механике стандартных дизейблов варкрафта, т.е карта команд не скрывается, вы неможите управлять юнитов но его очередь приказов не сбивается и приказы добавленные во время дизейбла будут выполнены после его окончания, если это конечно возможно, это чертовски удобно и правильно. Вспомните доту айсфрога, герой Axe заставляет атаковать себя с помощью одной абилки а при ваших приказах атаки у него прокает пассивка хотите вы в него зарядить спелл чтобы отталкнуть его от себя или застанить а неможите, его агр таймер который тупо приказывает атаковать его много раз в сек, когда агр закончится - вы стоите и ниче не делайте, нужно отдавать приказ чето делать, а жмакать кнопки во время агра себе дороже - чаще прокает пассивка!
Мемхаком же возможно сделать все похожие способности по человечески, выдаем флаг стана и следим за то что юнит получил приказ цель-обьект, юнит умер, время вышло, спелл рассеяли. Приказ нужно ослеживать обязательно, иначе на юнита под флагом стана перестанут действовать станы и все что основано на оглушении (все стандартные дизейблы не дающие двигаться + триггерная пауза), поэтому нам нужно узнать что юниту суют приказ стана, тут же убрать флаг стана, тогда стандартный дизейбл на него подействует и он будет в нем до его окончания, а как отследить его конец ! - правильно, по урону в 0 ед. и текущему приказу, триггер еще и урон должен отслеживать, какая туча событий на 1 юнита. Тут именнно и нужны динамические триггеры а таймеры не подходят по ряду причин.
Надеюсь я объяснил почему именно триггеры, поверь отравление наносящие только урон или какую-нибудь фрост нову я на триггерах бы не делал.
» WarCraft 3 / Аттач группы триггеров
Про unit indexer что такое?
Я думал о примерно таком коде: