Решил выложить используемую мной систему для отлова всякого-разного урона без лишних усилий. Конечно, это изобретение велосипеда, но возможно кому-то подойдет, тем более альтернативы на сайте я не увидел. И даже не поленился перевести её в 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...
не стал разбираться почему, но когда поместил систему в одну карту, начались страшные лаги, из за которых даже играть стало невозможно. естевственно лаги начались после регистра триггера.
rixt7956, тестировал на разных картах и лагов не заметил -> скорее всего проблема с триггере. Там урон не наносится? Если не сложно, скопируйте сюда код.
Спасибо за комментарии. Таймер использую просто потому, что боюсь пропажи способности из-за разных morph-заклинаний. Можно использовать UnitMakeAbilityPermanent(...) конечно, но говорят она не сильно надёжная...
GetHandleId(...) не подошёл, так как я хотел выдавать ID согласно common.j, а там номера хаотично расставлены.
Таймер использую просто потому, что боюсь пропажи способности из-за разных morph-заклинаний.
Да, кстати, система некорректно работает с морф-юнитами. Допустим, я ставлю демон хантера, пробую драться 1х1 с любым юнитом (например, орк бугай) - урон от обоих юнитов идет физический. После "перевоплощения", когда бугай бьет, система распознает два типа урона от орка - 1 физический и 1 магический, причем с одинаковыми значениями урона. После того, как "перевоплощение" закончилось, уже 3 типа урона (1 физический и 2 магических). А всё почему? Потому что на демон хантера при каждом "перевоплощении" вешается событие нанесения урона.
Вызов UnitMakeAbilityPermanent(targ, true, SPELL_MARK) после добавления способности SPELL_MARK должен решить вышеуказанную проблему. И ещё раз советую сделать добавление юнитов в систему через событие входа в регион.
Quote
GetHandleId(...) не подошёл, так как я хотел выдавать ID согласно common.j, а там номера хаотично расставлены.
Я бы не говорил этого, если бы не знал заранее и лишний раз не проверил. GetHandleId() выдает совершенно те самые значения.
Code
// как мы знаем: // constant damagetype DAMAGE_TYPE_DEFENSIVE=ConvertDamageType(21)
// попробуй исполнить код: call BJDebugMsg(I2S(GetHandleId(DAMAGE_TYPE_DEFENSIVE))) // или call BJDebugMsg(I2S(GetHandleId(ConvertDamageType(21))))
// любая из этих строк выведет на экран "21"
Функции типа ConvertSomeType() конвертируют целое число в тип, наследующий хендл, GetHandleId() конвертирует хендл в целое число - почему результаты на входе и выходе должны быть разными?
Ох, я забыл, что событие при превращении не исчезает. Тогда тут и выбора-то нет -> однозначно делать через вход в регион.
БТВ, если GetHandleId(...) сам по себе возвращает номер согласно common.j, то, возможно, мои функции не нужны вовсе.
Ещё думаю добавить проверку на зацикливание при неосторожном использовании (получил урон -> нанёс урон - > 100500 раз -> вылет). Нужно только узнать предельное число вызовов для ввода ограничения (и уточнить зависит ли оно от мощности машины).
Ещё думаю добавить проверку на зацикливание при неосторожном использовании
Насчет этого хотел сказать в первый раз, отвлекся на другие баги. Я думаю, достаточно будет завести глобальную переменную для проверки на повторное выполнение пользовательских триггеров.
Code
private bool DAMAGE_LOOP = true
// . . . if DAMAGE_LOOP then DAMAGE_LOOP = false int i = 0 while (i < count) { if TriggerEvaluate(user[i]) { TriggerExecute(user[i]) }; i++ } DAMAGE_LOOP = true }
Версия 1.2 с исправлением кучи багов и ещё пачкой новых... но не будем о грустном. Также добавил мануал и функцию ResetWidgetLife(...) для триггерного лечения. БТВ да, теперь игра не вылетит если случайно допустить зацикливание.
Разделил версии, теперь скачать cJass вариант вы можете здесь, а JASS2 - здесь.
Основная проблема сейчас - организовать работу системы во много "потоков". Ибо иначе функции начинают работать немного порой много неправильно при нанесении урона из триггера.
Ajaccio, если не сложно, можешь снова залить jass вариант ?
нужен моделлер/жассер для аниме карты по наруто Shinobi Final War(S.F.W.),пишите в лс. Подробности тут http://warcraft3ft.info/forum/26-34400-1#1335316
Borodach, я не чекал орбы и буфплейсеры, но что-то уловил про то, что цель получает "метку", посмотрел наработку - "метка" сделана на основе "Сфера проклятия". Последняя хавает и орб и буффплейсер, так что если это источник дамага непосредственно её вешает - увы нас ждёт игра без орбов и буффплейсеров. Во всяком случае без непосредственных.
SirNikolas, ок, оживший огонь мне запили... Нет можно конечно, но триггерное накладывание этого орба со всеми вытекающими - на мой взгляд самое геморное...
Добавлено (11 Октября 2012, 19:01:41) --------------------------------------------- Не следует забывать, что стакабельный урон от ожившего огня даёт бонусный вампиризм кстати.
Добавлено (11 Октября 2012, 19:02:09) --------------------------------------------- И.... ДА!
Добавлено (11 Октября 2012, 19:02:48) --------------------------------------------- Секундочку! Вампиризм же подавляет сферу проклятия! Точно будет прокать триггер, если маску смерти одеть???
Добавлено (11 Октября 2012, 19:04:00) --------------------------------------------- Ну хотя, используя такую систему придётся принять такую вещь, как маска смерти без вампиризма, как способности...
При импорте системы ты должен с ее помощью переписать все эффекты сфер. Так что маска смерти тоже триггерная будет => все будет нормально работать.
Ну ет само собой. Дошло уже. Постепенно доходят нюансы.
Quote (Naturekid)
Ну хотя, используя такую систему придётся принять такую вещь, как маска смерти без вампиризма, как способности...
Добавлено (11 Октября 2012, 19:09:12) ---------------------------------------------
Quote (SirNikolas)
Пассивка Урсы? Завтра сделаю.
Да нет-нет. Сделать-то можно, но геморновато. Хотя...хотя не геморно даже еси так подумать. Но это такой обман!
Добавлено (11 Октября 2012, 19:10:41) --------------------------------------------- Да не сложно ни фига. Полученный урон от дамми и пофиг мороз. Дать здоровья герою-хозяину...