Написал простенькую систему разброса урона, чисто jass без диалектов и мемхака.
Собственно, вопрос в том, оптимально ли это или есть какие-то неочевидные минусы, способные как-то навредить?
//attack -> add damage event -> function


function damaging takes nothing returns nothing
    local integer i = 0
    local integer h = GetHandleId(GetExpiredTimer())
    local unit damager = LoadUnitHandle(udg_data, h, 0)
    local unit damaged = LoadUnitHandle(udg_data, h, 1)
    local real radius = GetRandomReal(udg_minradius, udg_maxradius) 
    local location tmp = PolarProjectionBJ(GetUnitLoc(damaged), radius, GetRandomReal(0, 360))      
    local unit u = CreateUnit(GetOwningPlayer(damager), 'h000', GetLocationX(tmp), GetLocationY(tmp), 0 )  
    call SetUnitInvulnerable( damaged, false )
    call DestroyEffect(AddSpecialEffectLoc( udg_effect_name, tmp ))
    call UnitDamagePointLoc( u, 0, udg_damage_radius, tmp, udg_damage, ATTACK_TYPE_PIERCE, DAMAGE_TYPE_NORMAL ) 
    call RemoveUnit(u)
    set u = null
endfunction

function get_damage takes nothing returns nothing
    local timer t = CreateTimer()
    local integer h = GetHandleId(GetTriggeringTrigger())
    local unit damager = LoadUnitHandle(udg_data, h, 0)
    local unit damaged = LoadUnitHandle(udg_data, h, 1)
    local integer h = GetHandleId(t)                                     
    call SaveUnitHandle(udg_data, h, 0, damager)
    call SaveUnitHandle(udg_data, h, 1, damaged)
    call SetUnitInvulnerable( GetTriggerUnit(), true )
    call TimerStart(t, 0.0, false, function damaging)
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

function Trig_attacking_Conditions takes nothing returns boolean
    return GetUnitTypeId(GetAttacker()) == 'hrif'
endfunction

function Trig_attacking_Actions takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer h = GetHandleId(t)
    call TriggerRegisterUnitEvent( t, GetTriggerUnit(), EVENT_UNIT_DAMAGED )            
    call TriggerAddAction(t, function get_damage)
    call SaveUnitHandle(udg_data, h, 0, GetAttacker())
    call SaveUnitHandle(udg_data, h, 1, GetTriggerUnit())
endfunction

function InitTrig_attacking takes nothing returns nothing
    set gg_trg_attacking = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_attacking, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerAddCondition( gg_trg_attacking, Condition( function Trig_attacking_Conditions ) )
    call TriggerAddAction( gg_trg_attacking, function Trig_attacking_Actions )
endfunction

Нет, не оптимально, юзаешь точки вместо координат и даже не обнуляешь их, переменные юнитов тоже не обнулил, таймеры не обнуляешь, да и локальные триггеры тоже в null можно

local location tmp = PolarProjectionBJ(GetUnitLoc(damaged), radius, GetRandomReal(0, 360)) 
-->
local real x = GetUnitX(damaged)+radius*Cos(GetRandomReal(0,360)*bj_DEGTORAD))
local real y = GetUnitY(damaged)+radius*Sin(GetRandomReal(0,360)*bj_DEGTORAD))
local unit u = CreateUnit(GetOwningPlayer(damager), 'h000',x, y, 0 ) 
Координаты обнулять не нужно

call UnitDamagePointLoc( u, 0, udg_damage_radius, tmp, udg_damage, ATTACK_TYPE_PIERCE, DAMAGE_TYPE_NORMAL )
Функция дамажит всех без исключения если не ошибаюсь, лучше самим юнитом через цикл/группу дамажить юнитов

Ой посмотрел на это всё, вообще желательно всё переписать, зачем сохранять что-то в хэш-таблицу если ты уже создал триггер для этого
`
ОЖИДАНИЕ РЕКЛАМЫ...
23
Похожие вопросы:

ответ
Всё зависит от мелочей... если ты хочешь запаузить всех кто в данный момент находится на карте - это одно, если вообще ВСЕХ и ВСЁ - это другое...
Стомп застанит только тех, по кому попадёт... те кто появятся после - не будут застанены
Молотбурь застанит только тех, кого укажешь... кого не укажешь - не будут застанены
Пауза работать будет так же как молот, но так паузить баффы и прочее...
Можно собрать стан, который будет станить на 0.00 сек (вечно), а далее его снимать вручную... но тут надо учесть то что все станы должны будут это учитывать (или быть такими же - время таймерное).
. . .
По факту, когда я планировал перевести баффы на триггерную основу (тайминг), пришёл к выводу что мои баффы "обездвиживание" (сетка), "безмолвие" (сало), "обезоруживание" (дизарм - склад) и дополнительный бафф на "сковывание" (скорость поворота на 0), давали в сумме следующее:
  • нельзя двигаться и поворачиваться
  • нельзя кастовать
  • нельзя атаковать
В итоге это практически тот же стан... но с набором баффов в статусе (сетка и сало минимум)
ответ
Есть одна наработка - Dota helper, это dll которая подключается мемхаком к карте, дает много чего (в основном для доты), но там есть дабл клик, который реализован так: когда игрок нажал способность и пытается её кликнуть в область инетфейса, код из библиотеки мгновенно переносят курсор в позицию портрета, так как определение координат виджетов на экране уже есть, думаю автонаведение сделать вполне можно.
Но это уже C++ и поддержки нету, думайте и решайте все сами.

23
Могу сказать, что TriggerAddAction вызывает утечку памяти, если отдельно его не сохранять и позже удалять. Лучше через TriggerAddCondition вызывать действия триггера.
28
Нет, не оптимально, юзаешь точки вместо координат и даже не обнуляешь их, переменные юнитов тоже не обнулил, таймеры не обнуляешь, да и локальные триггеры тоже в null можно

local location tmp = PolarProjectionBJ(GetUnitLoc(damaged), radius, GetRandomReal(0, 360)) 
-->
local real x = GetUnitX(damaged)+radius*Cos(GetRandomReal(0,360)*bj_DEGTORAD))
local real y = GetUnitY(damaged)+radius*Sin(GetRandomReal(0,360)*bj_DEGTORAD))
local unit u = CreateUnit(GetOwningPlayer(damager), 'h000',x, y, 0 ) 
Координаты обнулять не нужно

call UnitDamagePointLoc( u, 0, udg_damage_radius, tmp, udg_damage, ATTACK_TYPE_PIERCE, DAMAGE_TYPE_NORMAL )
Функция дамажит всех без исключения если не ошибаюсь, лучше самим юнитом через цикл/группу дамажить юнитов

Ой посмотрел на это всё, вообще желательно всё переписать, зачем сохранять что-то в хэш-таблицу если ты уже создал триггер для этого
Принятый ответ
9
call TriggerAddCondition( gg_trg_attacking, Condition( function Trig_attacking_Conditions ) )
То есть, можно написать нечто в духе
call TriggerAddCondition( gg_trg_attacking, function Trig_attacking_Actions )
и оно будет работать?
Нет, не оптимально, юзаешь точки вместо координат и даже не обнуляешь их, переменные юнитов тоже не обнулил, таймеры не обнуляешь, да и локальные триггеры тоже в null можно
Хм, ясно. А хеш-таблицу по ключу не надо очищать?
А сама идея норм или есть лучше варианты? С тз алгоритма.

Функция дамажит всех без исключения если не ошибаюсь, лучше самим юнитом через цикл/группу дамажить юнитов
В данном случае так и задумывалось...
rsfghd:
Ой посмотрел на это всё, вообще желательно всё переписать, зачем сохранять что-то в хэш-таблицу если ты уже создал триггер для этого
Значения передавать...
28
Не нужно значения передавать, у тебя триггер реагирует на дамаг по этому юниту, ты уже можешь получить нужные тебе переменные с самого триггера

Как ты вообще сохранил карту без ошибок, если у тебя пересоздание переменной идёт?

закинул счётчик хэндлов, можешь посмотреть что происходит
Загруженные файлы
23
local code c=function Trig_attacking_Actions
call TriggerAddCondition( gg_trg_attacking, Filter(c) )
28
Сейчас попробую реализовать твою задумку, если никто не преуспеет)
9
Не нужно значения передавать, у тебя триггер реагирует на дамаг по этому юниту, ты уже можешь получить нужные тебе переменные с самого триггера
Хм, логично. Как-то не подумал.
rsfghd:
Как ты вообще сохранил карту без ошибок, если у тебя пересоздание переменной идёт?
Забавно. Ну как-то так получилось. Мб вар не считает это ошибкой?
makkad:
local code c=function Trig_attacking_Actions
call TriggerAddCondition( gg_trg_attacking, Filter(c) )
Хм, а что Filter делает?

закинул счётчик хэндлов, можешь посмотреть что происходит
Вылет в главное меню...
28
map_maiker, сохрани карту перед запуском

И возможно стоит проверить эти галочки, раз уж вар не выдал ошибку с пересозданием переменной
Загруженные файлы
9
map_maiker, сохрани карту перед запуском
У меня обычный редактор, если это имеет значение. Как-то не дошли пока руки поставить jngp.
23
map_maiker, Filter() - в твоём случае позволит подставить вместо функции, которая должна возвратить boolean, подставить функцию, которая возвращает nothing
28
map_maiker, лол, как ты вообще работаешь с кодом в обычном редакторе?
Многое теряешь без джнгп, и скорее всего, мою версию не заценишь
9
makkad:
map_maiker, Filter() - в твоём случае позволит подставить вместо функции, которая должна возвратить boolean, подставить функцию, которая возвращает nothing
Хм, любопытно.

rsfghd:
map_maiker, лол, как ты вообще работаешь с кодом в обычном редакторе?
Многое теряешь без джнгп, и скорее всего, мою версию не заценишь
jasscraft есть. Так-то, я раньше особо не писал на jass, недавно вот решил что гуи сковывает. Изначально я хотел на гуи написать эту систему, но вышла хрень. Неработающая как надо, что важно.
На счёт твоей версии - мб и заценю...
28
Ну в таком случае вот
раскрыть
Я не говорю, что это идеально, но чутка получше чем у тебя
library mylib initializer init
private group TempG = CreateGroup()
private trigger trg1 = CreateTrigger()

private function IsUnitDead takes unit u returns boolean
    return IsUnitType(u,UNIT_TYPE_DEAD) or GetUnitTypeId(u) < 1
endfunction

private function enemy takes nothing returns boolean
    set bj_lastReplacedUnit = GetFilterUnit()
    return not IsUnitDead(bj_lastReplacedUnit) and IsUnitEnemy(bj_lastReplacedUnit,GetOwningPlayer(bj_lastCreatedUnit))
endfunction

private function damage takes nothing returns nothing
    call UnitDamageTarget(bj_lastCreatedUnit,GetEnumUnit(),udg_damage,false,false,ATTACK_TYPE_PIERCE,DAMAGE_TYPE_NORMAL,null)
endfunction

private function damage1 takes nothing returns nothing
    local unit attacker = GetEventDamageSource()
    local unit damaged = GetTriggerUnit()
    local real rad = GetRandomReal(udg_minradius,udg_maxradius)
    local real a = GetRandomReal(0,360)*bj_DEGTORAD
    local real x = GetUnitX(damaged)+rad*Cos(a)
    local real y = GetUnitY(damaged)+rad*Sin(a)
    local boolexpr b = Condition(function enemy)
    
    call KillUnit(CreateUnit(Player(15),'u000',x,y,0))
    set bj_lastCreatedUnit = attacker
    call GroupEnumUnitsInRange(TempG,x,y,udg_damage_radius,b)
    call DisableTrigger(trg1)
    call ForGroup(TempG,function damage)
    call EnableTrigger(trg1)
    call GroupClear(TempG)
    set bj_lastCreatedUnit = null
    
    set attacker = null
    set damaged = null
    set b = null
endfunction

//===========================================================================
private function myfunc takes nothing returns nothing
    call TriggerRegisterUnitEvent(trg1,GetEnumUnit(),EVENT_UNIT_DAMAGED)
endfunction
private function Trig_d1_Actions takes nothing returns nothing
    call TriggerRegisterUnitEvent(trg1,GetTriggerUnit(),EVENT_UNIT_DAMAGED)
endfunction
//===========================================================================
private function mycond1 takes nothing returns boolean
    return GetUnitTypeId(GetTriggerUnit()) != 'u000'
endfunction
private function mycond takes nothing returns boolean
    return GetEventDamage() > 0. and GetUnitTypeId(GetEventDamageSource()) == 'hrif'
endfunction
private function init takes nothing returns nothing
    set gg_trg_d1 = CreateTrigger(  )
    call GroupEnumUnitsInRect(TempG,bj_mapInitialPlayableArea,null)
    call ForGroup(TempG,function myfunc)
    call GroupClear(TempG)
    call TriggerRegisterEnterRectSimple( gg_trg_d1, bj_mapInitialPlayableArea )
    call TriggerAddCondition(gg_trg_d1,Condition(function mycond1))
    call TriggerAddAction( gg_trg_d1, function Trig_d1_Actions )
    call TriggerAddCondition(trg1,Condition(function mycond))
    call TriggerAddAction(trg1,function damage1)
endfunction
endlibrary

Кстати, ты можешь делать намного интереснее вещи с триггерной атакой, вплоть до кривой цепной молнии скакающей по юнитам накладывающая дебаффы с отталкиванием и всей ерундой что только можешь придумать

Так-то, я раньше особо не писал на jass, недавно вот решил что гуи сковывает.
Чистый гуи да, но у тебя есть кастом скрипт, где можно обнулить точки и это всё, что в принципе нужно, чтобы эта система работала без утечек
Загруженные файлы
28
makkad:
Могу сказать, что TriggerAddAction вызывает утечку памяти, если отдельно его не сохранять и позже удалять. Лучше через TriggerAddCondition вызывать действия триггера.
А в чём разница? Это всё одно и тоже.

А по теме - динамическое создание триггеров тут не нужно.

Filter() - в твоём случае позволит подставить вместо функции, которая должна возвратить boolean, подставить функцию, которая возвращает nothing
Фильтр берёт коде, и возвращает фильтр, что подтип булеэкспры. А TriggerAddCondition принимает только булекспры.
23
PT153, Разница в утечке памяти. Вот тестовая карта. А удалять - это больше строчек на код тратить, конкретно в этом случае. Если sleep не нужен.
Загруженные файлы
28
makkad, убедил. TriggerClearActions и ResetTrigger не нужно, это ничего не удаляет.
23
PT153:
makkad, убедил. TriggerClearActions и ResetTrigger не нужно, это ничего не удаляет.
Да. И это тоже проверялось.
16
AddAction создает уникальный объект при каждом обращении, а AddCondition кэширует объекты. поэтому в динамических триггерах, где всё создается и разрушается множество раз за игру, нужно использовать именно Condition
Filter() и Condition() одно и то же
32
Детект урона что ты описал, уже есть на сайте и готовый, широко юзается в доте фрога - и это вызывает баги, не столь критичные но тем не менее, ибо замахиваясь ты провоцирует событие триггера, который создаёт еше 1 триггер, который ждёт любого урона по цели, что неправильно, во первых время существования триггера нужно, вдруг промах, так же событие смерти, если жертва умерла - то закругляемся.
Про кондишены правильно написал лич, ибо триггер акшин это объект, который сам по себе не удаляется.
9
Кстати, ты можешь делать намного интереснее вещи с триггерной атакой, вплоть до кривой цепной молнии скакающей по юнитам накладывающая дебаффы с отталкиванием и всей ерундой что только можешь придумать
Да, я знаю. Дамми-касты и всё такое. rsfghd:
Чистый гуи да, но у тебя есть кастом скрипт, где можно обнулить точки и это всё, что в принципе нужно, чтобы эта система работала без утечек
Я же не про утечки. Например, как в гуи прицепить функцию к таймеру?
PT153:
А по теме - динамическое создание триггеров тут не нужно.
А можно подробнее?
quq_CCCP:
во первых время существования триггера нужно, вдруг промах,
Да, в случае промаха урон просто откладывается. Но я не придумал как можно прицепить удаление триггера по времени. Самый правильный вариант - добавить событие в триггер, но... В общем, как это сделать чтобы работало - я не придумал.
28
map_maiker, юнит входит на карту, на него и добавляем событие на получение урона. Всё. А все эти костыли с событием на атаку бред. Тем более, что это замах, а не сама атака. И на каждый замах по новому триггеру - бред.
32
map_maiker, с мемхаком куда веселее, просто смотришь тип урона и атаки.
9
PT153:
map_maiker, юнит входит на карту, на него и добавляем событие на получение урона. Всё. А все эти костыли с событием на атаку бред. Тем более, что это замах, а не сама атака. И на каждый замах по новому триггеру - бред.
Звучит как создание одного громоздкого триггера...
quq_CCCP:
map_maiker, с мемхаком куда веселее, просто смотришь тип урона и атаки.
К мемхаку я только присматриваюсь. Издалека. Мб и до него руки дойдут.
28
Звучит как создание одного громоздкого триггера...
Что лучше, чем бред с постоянным созданием и удалением триггеров. Сколько писал на варе, ни разу такой дичи не потребовалось.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.