Решил выложить используемую мной систему для отлова всякого-разного урона без лишних усилий. Конечно, это изобретение велосипеда, но возможно кому-то подойдет, тем более альтернативы на сайте я не увидел. И даже не поленился перевести её в vJass...
Code
library EMDSystem initializer InitSystem
#include "cj_types.j"
define UnitDamageTarget = UserUnitDamageTarget
constant int SPELL_MARK = 'A003' //РАВ-код способности "Метка (Damage System)" constant int SPELL_BUFF = 'B000' //РАВ-код эффекта для "Метка (Damage System)"
private unit bj_lastSourceDamage private unit bj_lastTargetDamage private real bj_lastCountsDamage endglobals
function GetDSCounts takes nothing returns real return bj_lastCountsDamage endfunction
function GetDSSource takes nothing returns unit return bj_lastSourceDamage endfunction
function GetDSTarget takes nothing returns unit return bj_lastTargetDamage endfunction
private function FilterEvent takes nothing returns boolean local integer i = 0 if not (GetEventDamage() > 0.0) then return false endif set bj_lastCountsDamage = GetEventDamage() set bj_lastSourceDamage = GetEventDamageSource() set bj_lastTargetDamage = GetTriggerUnit() if (GetUnitAbilityLevel(bj_lastTargetDamage, SPELL_BUFF) != 0) then call UnitRemoveAbility(bj_lastTargetDamage, SPELL_BUFF) set bj_lastDamageType = DAMAGE_TYPE_NORMAL if (IsUnitType(bj_lastSourceDamage, UNIT_TYPE_HERO) == true) then set bj_lastAttackType = ATTACK_TYPE_HERO else set bj_lastAttackType = ATTACK_TYPE_MELEE endif else set bj_lastDamageType = DAMAGE_TYPE_MAGIC set bj_lastAttackType = ATTACK_TYPE_MAGIC endif loop exitwhen (user[i] == null) if TriggerEvaluate(user[i]) then call TriggerExecute(user[i]) endif set i = i + 1 endloop set bj_lastDamageType = null set bj_lastAttackType = null return false endfunction
private function CreateNewMember takes nothing returns boolean local unit targ = GetFilterUnit() if (GetWidgetLife(targ) > 0.0 and GetUnitAbilityLevel(targ, SPELL_MARK) == 0) then call TriggerRegisterUnitEvent(execute, targ, EVENT_UNIT_DAMAGED) call UnitAddAbility(targ, SPELL_MARK) endif set targ = null return false endfunction
function GetEventDamageType takes nothing returns damagetype return bj_lastDamageType endfunction
function GetEventAttackType takes nothing returns attacktype return bj_lastAttackType endfunction
function UserUnitDamageTarget takes unit c, unit t, real d, boolean a_b, boolean r_b, attacktype a_t, damagetype d_t, weapontype w_t returns boolean set bj_lastAttackType = a_t set bj_lastDamageType = d_t return UnitDamageTarget(c, t, d, a_b, r_b, a_t, d_t, w_t) endfunction
function TriggerRegisterAllUnitDamaged takes trigger t returns nothing local integer i = 0 loop exitwhen (user[i] == null) set i = i + 1 endloop set user[i] = t endfunction
private function TimerLoop takes nothing returns nothing local group timed = CreateGroup() call GroupEnumUnitsInRect(timed, bj_mapInitialPlayableArea, filter) call DestroyGroup(timed) set timed = null endfunction
private function InitSystem takes nothing returns nothing set filter = Condition(function CreateNewMember) call TriggerAddCondition(execute, Condition(function FilterEvent)) call TimerStart(CreateTimer(), 0.1, true, function TimerLoop) endfunction
endlibrary
Просто скопируйте к себе в карту триггер (при этом нужно иметь JNGP и, возможно, AdicParser), способность "Метка" и её эффект... Затем можете использовать новые функции:
1) TriggerRegisterAllUnitDamaged(<Триггер>) - новое событие, срабатывает при получении любым воинов урона. 2) GetDSSource, GetDSTarget и GetDSCounts - работают аналогично GetEventDamageSource, GetTriggerUnit и GetEventDamage соответственно. 3) GetEventAttackType и GetEventDamageType - возвращают, как ни странно, тип атаки и урона. 4) UserUnitDamageTarget - только для vJass версии, принимает те же параметры, что и UnitDamageTarget...
Действует на всех юнитов сразу... В этом и смысл ведь, можно просто писать разные способности а-ля "ударил и случилось N" или "герой поглощает N% урона от магии" и т.д.
Насчёт функций... Возможно переменными и проще, я просто старался сделать так, как это принято у Blizzard. Зачастую ведь они тоже используют переменные. Конечно, допустимо убрать приватность, тогда сохранится выбор. С группой всё верно, её стоит сделать глобальной и это снимет часть нагрузки. Впрочем исправляется порой строчек.
Я просто имитировал определение типа атаки и урона. Для начала, все на карте получают невидимую способность. Суть её такова, что при атаке враг получает эффект-пустышку. Далее срабатывает триггер получения урона. Если юнит имеет этот эффект, значит урон получен от атаки рукой, соответственно устанавливаю нужное значение переменной. Дополнительно стоит проверка, является атакующий героем или нет (и записываю тип атаки "геройский удар" или "обычный удар").
Конечно, если эффекта нет, значит урон получен от магии -> DAMAGE_TYPE_MAGIC и ATTACK_TYPE_MAGIC. Это не есть абсолютно верно, некоторые заклинания наносят другой тип урона, но они редкость. Тем более сейчас в картах редко используется стандарт, а триггерный урон я отлавливаю функцией.
После работы эффект-пустышка удаляется и его в игре не видно. Хотя, если наносить урон очень часто (вращение BM), то порой можно заметить мелькание в статусе.
Яд, как помню, вроде отображается на панели, хотя возможно есть и невидимый. Вообще меня страшно злят Blizzard'овские системы сфер и критов/башей. В итоге я их просто переписал с использование данной системы. После этого всё суммируется так, как мне нужно.
Яд, как помню, вроде, отображается на панели, хотя, возможно, есть и невидимый.
Невидимый spellbook.
Quote (Ajaccio)
Хотя, если наносить урон очень часто (вращение BM), то порой можно заметить мелькание в статусе.
При вращении у него атака становится равной нулю, но он продолжает атаковать и оставлять buff'ы.
Quote (Ajaccio)
Вообще меня страшно злят Blizzard'овские системы сфер и критов/башей. В итоге я их просто переписал с использование данной системы.
Дело в том, что даммикаст (например, замедления для яда) происходит с небольшой задержкой, что не есть красиво. Ты не знаешь, как это можно нормализовать?