WarCraft 3: Перезарядка пассивных предметов

» Раздел: Триггеры и объекты

Вид: Демонстрация метода (не наработка)
Требования: Последний патч (1.31 на момент написания)
Метод исполнения: Lua

Принцип работы перезарядки

» Кратко как работает
Добавляем в предмет абилку (амулета защиты) через функцию BlzItemAddAbility
Сбиваем линку вражеским даммиком и запускаем КД
Ждём отката КД и удаляем способность
Реально сделать и на 126 патче тоже самое, только придётся подменять предмет
Вот весь блок кода в принципе всё упрощено до 1 строчки в новой функции StartItemCD
function StartItemCD(it,c,idre)-- предмет, носитель предмета, ид способности по типу амулета защиты
BlzItemAddAbility(it, idre)
DummyCastOnUnit (nil,AbilityId('A001'),1,"creepthunderbolt",c)-- A001 пускатель перезарядки баша
cd=BlzGetAbilityCooldown(idre, 0)-- где 0 - первый уровень способности
TimerStart(CreateTimer(), cd, false, function()
BlzItemRemoveAbility(it, idre)   
end)
end
» Полный код метода
--общие функции
function AbilityId(id)
    return id:byte(1) * 0x1000000 + id:byte(2) * 0x10000 + id:byte(3) * 0x100 + id:byte(4)
end

function DummyCastOnUnit ( u, id, level, order,targ ) -- DummyCastOnUnit (u,'',1,"entanglingroots",targ) 
    local ud
    if u==nil then
        ud = CreateUnit(Player(2),AbilityId('e000'),GetUnitX(targ),GetUnitY(targ),0)
    else
        ud = CreateUnit(GetOwningPlayer(u),AbilityId('e000'),GetUnitX(u),GetUnitY(u),0)
    end
    UnitAddAbility(ud,id)
    SetUnitAbilityLevel(ud,id,level)
    IssueTargetOrder(ud,order,targ)
    UnitApplyTimedLife( ud, AbilityId('BTLF'), 1 )
end


function StartItemCD(it,c,idre)-- предмет, носитель предмета, ид способности по типу амулета защиты
BlzItemAddAbility(it, idre)
DummyCastOnUnit (nil,AbilityId('A001'),1,"creepthunderbolt",c)-- A001 пускатель перезарядки
cd=BlzGetAbilityCooldown(idre, 0)-- где 0 - первый уровень способности
TimerStart(CreateTimer(), cd, false, function()
BlzItemRemoveAbility(it, idre)   
end)
end




do -- cистема урона с руки
gg_trg_DamageEvent = CreateTrigger(  )
for i = 0, bj_MAX_PLAYER_SLOTS - 1, 1 do
    TriggerRegisterPlayerUnitEvent(gg_trg_DamageEvent, Player(i), EVENT_PLAYER_UNIT_DAMAGING)
    TriggerAddCondition( gg_trg_DamageEvent, Condition( function () return GetEventDamage()>1   end))
end
TriggerAddAction( gg_trg_DamageEvent, function ()

-- код функции сюда пишем условия
local u=GetTriggerUnit() -- тот кто получил урон
local c=GetEventDamageSource() -- тот кто нанёс урон
local d=GetEventDamage() -- число урона


-- блок башера
if BlzGetEventDamageType( ) == DAMAGE_TYPE_NORMAL  and  UnitHasItemOfTypeBJ(c, AbilityId('I000')) and GetUnitAbilityLevel(c, AbilityId('A000'))==0 then --
it=GetItemOfTypeFromUnitBJ(c, AbilityId('I000'))
SetItemCharges(it, GetItemCharges(it)+1) --увеличиваем заряды предмета за удар

if GetItemCharges(it)>=5 then
SetItemCharges(it, 0)
--print("прок баша, перезапуск")
DummyCastOnUnit (c,AbilityId('A001'),1,"creepthunderbolt",u)-- само оглушение башем
BlzSetEventDamage(d*2)-- увеличиваем входщий урон в 2 раза
StartItemCD(it,c,AbilityId('A000'))
end    
end
--- блок щита
if UnitHasItemOfTypeBJ(u, AbilityId('I001')) and GetUnitAbilityLevel(u, AbilityId('A003'))==0 then
    print("лечение щита")
it=GetItemOfTypeFromUnitBJ(u, AbilityId('I001')) -- помещаем в переменную предмет 
StartItemCD(it,u,AbilityId('A003'))-- стартуем кд на предмете
UnitAddItem(u, CreateItem(AbilityId('I002'), 0, 0))-- добавлением эффект лечения через руну
end

end)
end --конец блок кода урона

Плюсы метода

-Не сбивает текущий приказ
-может сработать даже в стане
-не конфликтует с амулетом защиты и другими подобными способностями

Минусы метода

-нельзя запустить кд, когда юнит полностью неуязвим
-нельзя запустить кд если юнит иммунен к магии (нужна переделка сбиваемой способности на канальную)
-слишком мало тестов
-не могу назвать это наработкой ибо слишком плохо знаю lua, так что делюсь просто фактом метода

Графические материалы


Просмотров: 591

konvan5 #1 - 3 месяца назад 0
Пора создавать полноценные статьи по Lua)
Чтоб было понятно даже тем, кто не шарит в джассе вовсе ;D
Bergi_Bear #2 - 3 месяца назад 1
Так а это что?
prog #3 - 3 месяца назад (отредактировано ) 0
Bergi_Bear, точно нет конфликтов с амулетом защиты? как гарантируется что амулет не сработает вместо нашей пустышки? Понимаю посему нет конфликта между двумя пустышками - пустышки добавляюся в нужный момент, но амулет то висит всегда, если его тоже не переводить на триггерные рельсы.
ScopteRectuS #4 - 3 месяца назад 0
AbilityId( ) можно заменить на нативную FourCC( ).
Bergi_Bear #5 - 3 месяца назад 2
ScopteRectuS, да можно, тут изъянов многоно
prog, а вот тут я сам и не понимаю, но я делал с амулетом защиты и всегда перезаряжается то что нужно, сам не понимаю какой тут алгоритм наверное по принципу "последняя добавленная способность"
prog #6 - 3 месяца назад 0
Bergi_Bear, боюсь, еще может подвести не мгновенность дамми-каста - что-то может вклиниться между добавлением способности и срабатыванием реакции на дамми-каст. Возможно в реальных условиях надо будет выдавать эту способность отслеживая каст даммика, а не до каста.
Bergi_Bear #7 - 3 месяца назад 0
prog, вообще если бы конфликтовало, я уже подготовил функцию по выкладываю "шальных" предметов или по удаление их способностей, но этого делать не пришлось
prog, не знаю о какой ты реакции дамми-каста, но в целом она есть там скоростью полёта снаряда максимальная и даммик создаётся вплотную в координатах максимум это может вызвать задержку в 0.000000001 (число от балды), но может же
prog #8 - 3 месяца назад 0
Bergi_Bear, я о времени между отдачей приказа даммику и срабатыванием нашей пустышки в предмете. Даже правильно настроенный даммик потратит какое-то время на каст.

А так - костыль интересный, возьму на вооружение.
Bergi_Bear #9 - 3 месяца назад 0
даммик без модели не имеет же каст поинтов и срабатывает мгновенно
prog #10 - 3 месяца назад 0
А еще - не забывай удаление таймера. Луа не требует обнуления переменных, но удалять нативные объекты всеравно надо. Одноразовый таймер же вроде не удаляет себя сам, если я правильно помню.
Bergi_Bear #11 - 3 месяца назад 0
А когда его удалять? сразу же в его функции создания через Destroy?
prog #12 - 3 месяца назад 1
Bergi_Bear, удалять сразу после срабатывания, естественно, иначе как же он сработает.
ScorpioT1000 #13 - 3 месяца назад (отредактировано ) 0
Людоедский код, юзай хотябы онлайн бьютифай blackmiaool.com/lua-beautify
» done
--общие функции
function AbilityId(id)
    return id:byte(1) * 0x1000000 + id:byte(2) * 0x10000 + id:byte(3) * 0x100 + id:byte(4)
end

function DummyCastOnUnit ( u, id, level, order,targ ) -- DummyCastOnUnit (u,'',1,"entanglingroots",targ)
    local ud
    if u==nil then
        ud = CreateUnit(Player(2),AbilityId('e000'),GetUnitX(targ),GetUnitY(targ),0)
    else
        ud = CreateUnit(GetOwningPlayer(u),AbilityId('e000'),GetUnitX(u),GetUnitY(u),0)
    end
    UnitAddAbility(ud,id)
    SetUnitAbilityLevel(ud,id,level)
    IssueTargetOrder(ud,order,targ)
    UnitApplyTimedLife( ud, AbilityId('BTLF'), 1 )
end


function StartItemCD(it,c,idre)-- предмет, носитель предмета, ид способности по типу амулета защиты
    BlzItemAddAbility(it, idre)
    DummyCastOnUnit (nil,AbilityId('A001'),1,"creepthunderbolt",c)-- A001 пускатель перезарядки
    cd=BlzGetAbilityCooldown(idre, 0)-- где 0 - первый уровень способности
    TimerStart(CreateTimer(), cd, false, function()
        BlzItemRemoveAbility(it, idre)
    end)
end




do -- cистема урона с руки
    gg_trg_DamageEvent = CreateTrigger(  )
    for i = 0, bj_MAX_PLAYER_SLOTS - 1, 1 do
        TriggerRegisterPlayerUnitEvent(gg_trg_DamageEvent, Player(i), EVENT_PLAYER_UNIT_DAMAGING)
        TriggerAddCondition( gg_trg_DamageEvent, Condition( function () return GetEventDamage()>1   end))
    end
    TriggerAddAction( gg_trg_DamageEvent, function ()

            -- код функции сюда пишем условия
            local u=GetTriggerUnit() -- тот кто получил урон
            local c=GetEventDamageSource() -- тот кто нанёс урон
            local d=GetEventDamage() -- число урона


            -- блок башера
            if BlzGetEventDamageType( ) == DAMAGE_TYPE_NORMAL  and  UnitHasItemOfTypeBJ(c, AbilityId('I000')) and GetUnitAbilityLevel(c, AbilityId('A000'))==0 then --
                it=GetItemOfTypeFromUnitBJ(c, AbilityId('I000'))
                SetItemCharges(it, GetItemCharges(it)+1) --увеличиваем заряды предмета за удар

                if GetItemCharges(it)>=5 then
                    SetItemCharges(it, 0)
                    --print("прок баша, перезапуск")
                    DummyCastOnUnit (c,AbilityId('A001'),1,"creepthunderbolt",u)-- само оглушение башем
                    BlzSetEventDamage(d*2)-- увеличиваем входщий урон в 2 раза
                    StartItemCD(it,c,AbilityId('A000'))
                end
            end
            --- блок щита
            if UnitHasItemOfTypeBJ(u, AbilityId('I001')) and GetUnitAbilityLevel(u, AbilityId('A003'))==0 then
                print("лечение щита")
                it=GetItemOfTypeFromUnitBJ(u, AbilityId('I001')) -- помещаем в переменную предмет
                StartItemCD(it,u,AbilityId('A003'))-- стартуем кд на предмете
                UnitAddItem(u, CreateItem(AbilityId('I002'), 0, 0))-- добавлением эффект лечения через руну
            end

    end)
end --конец блок кода урона
quq_CCCP #14 - 3 месяца назад 0
Эмм, кстати никто не проверял на взаимодействие с инивзами? То я что то забыл упомянуть, но точно помню что эксгумация срабатывая сбивает все инвизы с владельца, что не комильфо, амулет защитый работает аналогичным образом, юнит получает приказ его каста.
Насчет 1.26+ и луа, а там еще не завезли StartAbilityCooldown?
NazarPunk #15 - 3 месяца назад 0
а там еще не завезли StartAbilityCooldown?
С кулдаунами таже печаль.
Bergi_Bear #16 - 3 месяца назад 0
quq_CCCP, нет инвиз не проверял, по кулдаунам функций, если раньше амулет выводил из инвиза? то и щас скоре всего та же беда
Хотя не могу представить себе ситуацию где бежит БХ в инвизе и с линкой, ему сбивают линку и он выходит из инвиза, неужели так в первой доте было?
quq_CCCP #17 - 2 месяца назад 0
Bergi_Bear, ну там много чего сбивало инвиз, а учитывая кол-во багов, этот не самый страшный. Химик во время ульта уходит в инвиз от лотара, у него кончается ульт и он выходит из инвиза, т.к морф кастуется пассивным кастом, чтобы химик мог превратится обратно. В бложике лича читаем.
Эксгумацию я проверял лично - сбивает инвиз при каждом кд. По этому спеллнигейшин не надежный и баганый вариант.
NazarPunk #18 - 1 месяц назад (отредактировано ) 1
Пора создавать полноценные статьи по Lua)
Начало положено))