Пишу такую способность на JASS:
При атаке атакующий юнит получает дополнительный урон, который стакается, если юнит атаковал снова в течении 5 секунд. Для этого я запускаю таймер, который через 5 секунд удалит дополнительный урон у юнита. Настакиванье урона я делаю при помощи изменения уровня скилла +урон. Но никак не могу понять: каким образом при повторной атаке сбросить таймер на 0.00. Думаю, мой вопрос банален для прожженных кодеров. Я искал некоторые статьи или похожие вопросы, но ответа не нашел. Подскажите как такое решается или дайте ссылки на похожие вопросы или статьи по теме. Заранее, спасибо.
Код скилла (на всякий случай):
function Trig_Aura_Strenght_Conditions takes nothing returns boolean
    if ( not ( GetUnitAbilityLevelSwapped('S000', GetAttacker()) == 1 ) ) then
        return false
    endif
    if ( not ( GetRandomInt(1, 1) == 1 ) ) then
        return false
    endif
    return true
endfunction

function Aura_Strenght_Lost takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer id = GetHandleId(t)
    local unit caster = LoadUnitHandle(udg_Hash,id,47)
    local real time = LoadReal(udg_Hash,id,48)
    
    set time = time + 0.05
    call SaveReal(udg_Hash,id,48,time)
    if time == 5.00 then
        call UnitRemoveAbility(caster,'S001')
        call DestroyTimer(t)
        call FlushChildHashtable(udg_Hash,id)
    endif
    call BJDebugMsg(R2S(time))
endfunction

function Trig_Aura_Strenght_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local integer id = GetHandleId(t)
    local unit caster = GetAttacker()
    call UnitAddAbility(caster,'S001')
    call SetUnitAbilityLevel(caster,'S001',1)
    call SaveUnitHandle(udg_Hash,id,47,caster)
    call SaveReal(udg_Hash,id,48,0.00)
    call TimerStart(t,0.05,true,function Aura_Strenght_Lost)
    //call AddHeroXP(caster,100,true)
endfunction

//===========================================================================
function InitTrig_Aura_Strenght takes nothing returns nothing
    set gg_trg_Aura_Strenght = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Aura_Strenght, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerAddCondition( gg_trg_Aura_Strenght, Condition( function Trig_Aura_Strenght_Conditions ) )
    call TriggerAddAction( gg_trg_Aura_Strenght, function Trig_Aura_Strenght_Actions )
endfunction

Принятый ответ

8gabriel8, я скинул наработку, которая реализует общее событие «получает урон» в 30 строк, для её использования даже думать как именно она работает не нужно.
`
ОЖИДАНИЕ РЕКЛАМЫ...
0
6
6 лет назад
0
Блин, почитай свой вопрос еще раз сам. Я вот не понял, что тебе в конце концов нужно. Урон не "отнимается" а наносится, в твоем случае.
0
28
6 лет назад
0
каким образом при повторной атаке сбросить таймер на 0.00
Каждый раз стартуй его заново.
1
32
6 лет назад
1
Очень баганая реализация с атакой, нужно отслеживать урон, это раз, два ненадо использовать конверт из гуи, not( some cond == false ),
Детект урона в помощь, системы бонус урона были на сайте, после каждого удара просто повышаешь счетчик на +1 ну и запускаешь таймер который снимит бонус.
2
28
6 лет назад
Отредактирован PT153
2
Во-первых, измени событие на получение урона, а не на срабатывание атаки.
А во-вторых, у тебя при каждой атаке плодятся таймеры.

Вот нормальная реализация.
index -- любое удобное для тебя число.
// Эта функции вообще не нужна
function Trig_Aura_Strenght_Conditions takes nothing returns boolean
    return true
endfunction

function Aura_Strenght_Lost takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer tid = GetHandleId(t)
    local unit caster = LoadUnitHandle(udg_Hash,tid,47)
    local integer cid = GetHandleId(caster)
    call FlushChildHashtable(udg_Hash, tid)
    call RemoveSavedHandle(udg_Hash, cid)
    call UnitRemoveAbility(caster,'S001')
    call DestroyTimer(t)
    set t = null
endfunction

function Trig_Aura_Strenght_Actions takes nothing returns nothing
    local unit caster = GetAttacker()
    local integer cid = GetHandleId(caster)
    local timer t = LoadTimerHandle(udg_Hash, cid, index)
    local integer level
    local integer tid
    if t == null then
        set t = CreateTimer()
        call SaveTimerHandle(udg_Hash, cid, index, t)
        set tid = GetHandleId(t)
        call SaveUnitHandle(udg_Hash, tid, 47, caster)
        call SaveInteger(udg_Hash, tid, 47, 1)  // НЕ перезапишет юнита
        call UnitAddAbility(caster, 'S001')
    else
        set tid = GetHandleId(t)
        set level = LoadTimerHandle(udg_Hash, cid, index) + 1
        call SetUnitAbilityLevel(caster, 'S001', level)
        call SaveInteger(udg_Hash, tid, 47, level)
    endif
    call TimerStart(t, 5., false, function Aura_Strenght_Lost)
    set t = null
    set caster = null
endfunction
0
5
6 лет назад
0
Globder:
Блин, почитай свой вопрос еще раз сам. Я вот не понял, что тебе в конце концов нужно. Урон не "отнимается" а наносится, в твоем случае.
Юнит бьет, получает +урон, потом бьет еще - +урон становится больше, +10,+20,+30, но если прошло 5 секунд, то +урон весь пропадает. Не получается перезапустить таймер.
UPD: крутил-крутил-вертел код, сделал так, вроде, работает, но мне кажется, что можно лучше
function Trig_Aura_Strenght_Conditions takes nothing returns boolean
    if ( not ( GetUnitAbilityLevelSwapped('A00B', GetAttacker()) == 1 ) ) then
        return false
    endif
    if ( not ( GetRandomInt(1, 1) == 1 ) ) then
        return false
    endif
    return true
endfunction

function Aura_Strenght_Lost takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer id = GetHandleId(t)
    local unit caster = LoadUnitHandle(udg_Hash,id,47)
    local integer caster_id = GetHandleId(caster)
    local real time = LoadReal(udg_Hash,caster_id,200)
    
    set time = time + 0.05
    call SaveReal(udg_Hash,caster_id,200,time)
    if time == 5.00 then
        call UnitRemoveAbility(caster,'A00V')
        call DestroyTimer(t)
        call FlushChildHashtable(udg_Hash,id)
        call FlushChildHashtable(udg_Hash,caster_id)
    endif
    call BJDebugMsg(R2S(time))
endfunction

function Trig_Aura_Strenght_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local integer id = GetHandleId(t)
    local unit caster = GetAttacker()
    local integer caster_id = GetHandleId(caster)
    local integer ability_level = LoadInteger(udg_Hash,caster_id,201)
    local real time = 0.00
    call SaveUnitHandle(udg_Hash,id,47,caster)
    set ability_level = ability_level + 1
    call SaveInteger(udg_Hash,caster_id,201,ability_level)
    if GetUnitAbilityLevelSwapped('A00V',caster) == 0
        call UnitAddAbility(caster,'A00V')
        call SetUnitAbilityLevel(caster,'A00V',ability_level)
        call TimerStart(t,0.05,true,function Aura_Strenght_Lost)
    elseif GetUnitAbilityLevelSwapped('A00V',caster) >= 1
        call BJDebugMsg("Матерное слово")
        set time = 0.00
        call SaveReal(udg_Hash,caster_id,200,time)
        call SetUnitAbilityLevel(caster,'A00V',ability_level)
    endif
    //call AddHeroXP(caster,100,true)
endfunction

//===========================================================================
function InitTrig_Aura_Strenght takes nothing returns nothing
    set gg_trg_Aura_Strenght = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Aura_Strenght, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerAddCondition( gg_trg_Aura_Strenght, Condition( function Trig_Aura_Strenght_Conditions ) )
    call TriggerAddAction( gg_trg_Aura_Strenght, function Trig_Aura_Strenght_Actions )
endfunction
2
28
6 лет назад
Отредактирован PT153
2
крутил-крутил-вертел код, сделал так, вроде, работает, но мне кажется, что можно лучше
У тебя всё равно плодятся таймеры при каждом замахе. Через несколько минут игры будут лаги. Лучше глянь сообщение над своим.
Они бы не плодились, если бы была проверка на наличие способности, которую добавляешь (если уровень способности больше нуля, ничего не делаем). Но такой проверки нет.

Нашёл ошибку в своей реализации, исправил.
0
26
6 лет назад
Отредактирован Extremator
0
Да просто при замахе проверяешь есть ли абилка (которая гарантирует эффект повышения урона при атаке). Запускаешь таймер на 5 сек (можно его сначала остановить и тут же запустить на новое время). Дальше смотришь есть ли абилка на повышение урона, если нет - даёшь её... если есть - повышаешь её уровень на +1.
Это легко делается на GUI, а на Jass'е делаешь то же самое, но с нужными тебе исправлениями...
0
5
6 лет назад
0
PT153:
крутил-крутил-вертел код, сделал так, вроде, работает, но мне кажется, что можно лучше
У тебя всё равно плодятся таймеры при каждом замахе. Через несколько минут игры будут лаги. Лучше глянь сообщение над своим.
Они бы не плодились, если бы была проверка на наличие способности, которую добавляешь (если уровень способности больше нуля, ничего не делаем). Но такой проверки нет.

Нашёл ошибку в своей реализации, исправил.
И такой способ для события Получает урон? То есть если нет таймера, то он создаст его, а если таймер есть, то он увеличит уровень способности? (я немного запутался просто)
0
28
6 лет назад
0
То есть если нет таймера, то он создаст его, а если таймер есть, то он увеличит уровень способности? (я немного запутался просто)
Да, ведь так должен спел работать? Я из описания вопроса так понял.
И такой способ для события Получает урон?
Событие "Юнит атакован" срабатывает во время замаха. Это можно абузить. Для каждого юнита на карте нужно зарегистрировать событие по получению урона. Для каждого, потому что общей такой функции нет.
0
5
6 лет назад
0
PT153:
То есть если нет таймера, то он создаст его, а если таймер есть, то он увеличит уровень способности? (я немного запутался просто)
Да, ведь так должен спел работать? Я из описания вопроса так понял.
И такой способ для события Получает урон?
Событие "Юнит атакован" срабатывает во время замаха. Это можно абузить. Для каждого юнита на карте нужно зарегистрировать событие по получению урона. Для каждого, потому что общей такой функции нет.
А как создать событие Получает урон, если такой функции нет?
quq_CCCP:
Очень баганая реализация с атакой, нужно отслеживать урон, это раз, два ненадо использовать конверт из гуи, not( some cond == false ),
Детект урона в помощь, системы бонус урона были на сайте, после каждого удара просто повышаешь счетчик на +1 ну и запускаешь таймер который снимит бонус.
Можно ссылочку, плиз. Я вроде просматривал какие-то материалы. Может пропустил...
0
28
6 лет назад
Отредактирован PT153
0
А как создать событие Получает урон,
Есть для определённого юнита. Если есть юниты на карте, регистрируем для них. Для юнитов, что создаются во время игры, надо сделать такой триггер.
Событие. Юнит - Юнит входит в область Вся карта.
Действие. Триггер - Добавить событие такому-то триггеру Вошедший юнит Получает урон.
0
32
6 лет назад
0
Ну щяс прям не скажу, ну гуглите "детект физического урона" он есть и на мемхаке и без мемхака.
1
26
6 лет назад
1
Вот нахрена вешать ивенты на каждого юнита в игре?
Ведь можно вешать только на тех, кто будет атакован с такой абилкой... Нее?
0
21
6 лет назад
0
Extremator, и как же ты это сделаешь?
нет, у меня есть система постоянного отслеживания тех кто рядом с обладателем определенной абилки в зависимости от дальности атаки и являющихся его врагами, но это сам понимаешь не просто
вот еще раз выбешиваешься что нет события UNIT АТАКУЕТ, как же збс было бы с ним
0
26
6 лет назад
0
ClotPh:
и как же ты это сделаешь?
Серьёзно? Разве это не очевидно?
Событие - юнит атакован
Условие - у атакующего есть абилка X
Действие - создать ивент для атакованного (+фильтр)
где X - абилка, которая позволяет атакующему юниту (т.е. её обладателю) атаковать и при этом повышать силу своей атаки... (ну условная пустышка, сам скилл без ничего)
Нее?
0
28
6 лет назад
Отредактирован PT153
0
Ведь можно вешать только на тех, кто будет атакован с такой абилкой... Нее?
Но ведь атакованы могут быть все.
Extremator:
Нее?
И каждый раз, когда юнит будет атакован юнитом со способностью X, будет добавляться событие, из-за чего триггер будет срабатывать кучу раз для атакованного юнита.
PT153:
UNIT АТАКУЕТ
Его просто сделать, если добавить фильтр в событие UNIT_ATTACKED. Фильт отлавливает только того, кто атакует, как ни странно.
0
26
6 лет назад
Отредактирован 8gabriel8
0
PT153, Extremator указал в скобках +фильтр, тебе не кажется, что это что-то должно значить?
0
28
6 лет назад
Отредактирован PT153
0
указал в скобках +фильтр, тебе не кажется, что это что-то должно значить?
В фильтре можно только прочекать GetFilterUnit(), а для события получения урона GetFilterUnit() возвращает наносителя.

Да и как ты проверишь, что для этого юнита уже зарегистрировано событие без создания доп. костылей?
Само событие UNIT_ATTACKED сильно нагружает игру, потому что срабатывает каждый раз при замахе. У меня из-за частого срабатывания этого события сильно глючила игра. А событие на вход во всю карту срабатывает 1 раз за игру.
Решение Extremator требует сохранения boolean, которое будет отвечать за регистрацию такого события и будет уникально для каждого юнита. И оно также может вызывать лаги. Потому с точки зрения оптимизации и с точки зрения простоты способ ниже самый лучший, если получить урон может любой юнит. Если не любой, то просто в условии или в фильтре отсеиваем ненужных.
Событие. Юнит - Юнит входит в область Вся карта.
Действие. Триггер - Добавить событие такому-то триггеру Вошедший юнит Получает урон.
0
23
6 лет назад
0
GetAttacked это котоырый юнит получает юрон
GetAttacker это атакующий юнит
0
26
6 лет назад
Отредактирован 8gabriel8
0
PT153, создаёшь группу, в триггере с событием Юнит Атакован делаешь условие, что атакованный не в группе, в действия добавляешь событие Юнит Получает урон с ним в триггер на получение урона.
0
28
6 лет назад
0
создаёшь группу
Но зачем, когда можно просто регистрировать во время входа. 1 добавленное событие проще 1000 срабатываний триггера с проверкой.
Само событие UNIT_ATTACKED сильно нагружает игру
0
26
6 лет назад
Отредактирован 8gabriel8
0
И есть ведь вроде действие, которое возвращает изначальное состояние триггера до добавления в него событий, условий и действий?
Но зачем, когда можно просто регистрировать во время входа
PT153, человек жаловался в своё время, что через минут 10-30 интенсивного спавна с этим добавлением события начинало сильнейше лагать.
0
28
6 лет назад
0

Способ с событием Вся карта и условием отсеивающее ненужных юнитов.
Плюсы.
  • Простой
  • Не нагружает игру
Минусы.
  • Зарегистрированный юнит возможно так и не будет атакован

Способ Extremator.
Плюсы.
  • Регистрирует не всех юнитов.
Минусы.
  • Для верной работы требуется создание доп. объектов.
  • Постоянно срабатывает во время игры.
  • Зарегистрированный юнит возможно так и не будет атакован, так как UNIT_ATTACKED срабатывает при замахе.

сильнейше лагать
Сильнейше лагать будет и от UNIT_ATTACKED, так что такой способ определённо не выход.
8gabriel8:
И есть ведь вроде действие, которое возвращает изначальное состояние триггера до добавления в него событий, условий и действий?
Есть такое, но я не знаю, так ли оно работает, как ты описал.
native ResetTrigger takes trigger whichTrigger returns nothing
0
26
6 лет назад
0
PT153:
Сильнейше лагать будет и от UNIT_ATTACKED
Ни разу не сталкивался, пример есть? С условием, что атакующий какой-то один герой
0
21
6 лет назад
0
Если бы было событие UNIT_ATTACKING, то можно было бы регистрировать на него ТОЛЬКО обладателей нужных нам пассивок, срабатывающих при ИХ атаке и не париться из-за лагов, в этом вся разница
примерно так же например можно - и так, ятп, и делается везде - на пассивку акса при выучивании его пассивки зарегистрировать на UNIT_ATTACKED ТОЛЬКО акса, но там-то как раз ATTACKED, т. е. срабатывает при атаке НА НЕГО
в общем, с пассивками, срабатывающими для атакованных юнитов при атаке НА НИХ проблем нет
а от пассивок, срабатывающих для атакующих при ИХ атаке КОГО УГОДНО ДРУГОГО - есть
потому что в первом случае достаточно регистрировать событие только для одного-единственного обладателя пассивки
а во втором нужно отлавливать всех этих "КОГО УГОДНО ДРУГИХ" (как минимум - ближайших и способных быть атакованными)
Чтобы оставить комментарий, пожалуйста, войдите на сайт.