Добавлен , опубликован
Способ реализации:
Версия Warcraft:

Божественный щит

MUI: да
Импорт: нет
Требования: JNGP
Идея : Bergi_Bear
Описание: Пассивно активируется божественный щит всякий раз, когда здоровье героя падает ниже отметки в 10%. Перезарядка: 20, длительность: 5.

Скринншот

Технические подробности

Перенос в свою карту
Способности
  • 'Asds' Божественный щит (заклинание)
Предметы
  • 'Idsp' Божественный щит
  • 'Idsa' Божественный щит
Триггеры
  • ItemDivineShield
Настройки
constant integer ITEM_ACTIVE = 'Idsa'; // Активный предмет
constant integer ITEM_PASSIVE = 'Idsp'; // Пассивный предмет
constant real ITEM_ABILITY_COOLDOWN = 20; // Перезарядка способности предмета

trigger DAMAGE_DETECT_TRIGGER = CreateTrigger(); // Не трогать
region MAP_REGION;  // Не трогать

hashtable HT = InitHashtable(); // Хэштаблица, можете вписать туда вашу, например:
// hashtable HT = udg_HashTable;
Код заклинания
// !nocjass
//! zinc
library ItemDivineShield {
    
    constant integer ITEM_ACTIVE = 'Idsa'; // Активный предмет
    constant integer ITEM_PASSIVE = 'Idsp'; // Пассивный предмет
    constant real ITEM_ABILITY_COOLDOWN = 20; // Перезарядка способности предмета

    trigger DAMAGE_DETECT_TRIGGER = CreateTrigger(); // Не трогать
    region MAP_REGION;  // Не трогать
    
    hashtable HT = InitHashtable(); // Хэштаблица, можете вписать туда вашу, например:
    // hashtable HT = udg_HashTable;
    
    
    /*
    *
    *
    *
    *
    *
    */
    
    function isUnitAlive(unit target) -> boolean {
        return GetWidgetLife(target) > 0.405;
    }
    
    function itemReplaceInstantly(unit u, integer from, integer to){
        integer i, slot[], slotI = -1;
        item it;
        for(0 <= i < bj_MAX_INVENTORY){
            it = UnitItemInSlot(u, i);
            if (GetItemTypeId(it) == from){
                RemoveItem(it);
                slotI = slotI + 1;
                slot[slotI] = i;
            }
        }
        for(0 <= i <= slotI){
            UnitAddItemToSlotById(u, to, slot[i]);
        }
        it = null;
    }
    
    function itemReplaceDelayed(unit u, integer from, integer to){
        timer t = CreateTimer();
        integer pk = GetHandleId(t);
        SaveUnitHandle(HT, pk, 0, u);
        SaveInteger(HT, pk, 0, from);
        SaveInteger(HT, pk, 1, to);
        TimerStart(t, 0.03125, true, function(){
            timer t = GetExpiredTimer();
            integer pk = GetHandleId(t);
            unit u = LoadUnitHandle(HT, pk, 0);
            if (isUnitAlive(u)){
                itemReplaceInstantly(u, LoadInteger(HT, pk, 0), LoadInteger(HT, pk, 1));
                FlushChildHashtable(HT, pk);
                PauseTimer(t); DestroyTimer(t);
            }
            u = null;
            t = null;
        });
        t = null;
    }
    
    function itemReplace(unit u, integer from, integer to){
        if (isUnitAlive(u)){
            itemReplaceInstantly(u, from, to);
        } else {
            itemReplaceDelayed(u, from, to);
        }
    }
    
    function itemCount(unit u, integer c) -> integer {
        integer i, count = 0;
        item it;
        for(0 <= i < bj_MAX_INVENTORY){
            it = UnitItemInSlot(u, i);
            if(GetItemTypeId(it) == c){
                count = count + 1;
            }
        }
        it = null;
        return count;
    }

    function addUnitToDetect() -> boolean {
        unit u = GetFilterUnit();
        if (IsUnitType(u, UNIT_TYPE_HERO)){
            TriggerRegisterUnitEvent(DAMAGE_DETECT_TRIGGER, u, EVENT_UNIT_DAMAGED);
        }
        u = null;
        return false;
    }
    
    function onInit(){
        trigger t[];
        integer i;
        group g = CreateGroup();
        
        for(0 <= i <= 2){ t[i] = CreateTrigger(); }
        
        MAP_REGION = CreateRegion();
        RegionAddRect(MAP_REGION, bj_mapInitialPlayableArea);
        
        t[0] = CreateTrigger();
        TriggerRegisterEnterRegion(t[0], MAP_REGION, null);
        TriggerAddCondition(t[0], function addUnitToDetect);
        
        GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, function addUnitToDetect);
        GroupClear(g); DestroyGroup(g); g = null;
        
        TriggerAddCondition(DAMAGE_DETECT_TRIGGER, Condition(function() -> boolean {
            unit u = GetTriggerUnit();
            item it;
            integer i, pk;
            real dmg = GetEventDamage();
            timer t;
            if (
                dmg > 0
                &&
                GetUnitCurrentOrder(u) != 851973
                &&
                itemCount(u, ITEM_PASSIVE) > 0
                &&
                GetWidgetLife(u) - dmg <= GetUnitState(u, UNIT_STATE_MAX_LIFE) * 0.1
            ){                
                itemReplace(u, ITEM_PASSIVE, ITEM_ACTIVE);
                for(0 <= i < bj_MAX_INVENTORY){
                    it = UnitItemInSlot(u, i);
                    if(GetItemTypeId(it) == ITEM_ACTIVE){
                        UnitUseItem(u, it);
                        break;
                    }
                }
                
                t = CreateTimer();
                pk = GetHandleId(t);
                SaveUnitHandle(HT, pk, 0, u);
                TimerStart(t, ITEM_ABILITY_COOLDOWN - 0.01, false, function(){
                    timer t = GetExpiredTimer();
                    integer pk = GetHandleId(t);
                    unit u = LoadUnitHandle(HT, pk, 0);
                    itemReplace(u, ITEM_ACTIVE, ITEM_PASSIVE);
                    u = null;
                    FlushChildHashtable(HT, pk);
                    PauseTimer(t); DestroyTimer(t); t = null;
                });
            }
            
            u = null;
            it = null;
            t = null;
            return false;
        }));
        
        for(0 <= i < bj_MAX_PLAYER_SLOTS){
            TriggerRegisterPlayerUnitEvent(t[1], Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, null);
            TriggerRegisterPlayerUnitEvent(t[2], Player(i), EVENT_PLAYER_UNIT_DEATH, null);
        }
        TriggerAddCondition(t[1], Condition(function() -> boolean {
            unit u = GetTriggerUnit();
            item it = GetManipulatedItem();
            
            if (GetItemTypeId(it) == ITEM_PASSIVE && itemCount(u, ITEM_ACTIVE) > 0){
                itemReplace(u, ITEM_PASSIVE, ITEM_ACTIVE);
            }
            u = null;
            it = null;
            return false;
        }));
        TriggerAddCondition(t[2], Condition(function() -> boolean {
            unit u = GetTriggerUnit();
            if (itemCount(u, ITEM_ACTIVE) > 0){
                itemReplace(u, ITEM_ACTIVE, ITEM_PASSIVE);
            }
            u = null;
            return false;
        }));
        
        for(0 <= i <= 2){t[i] = null;}
    }
}
//! endzinc
// !endnocjass
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
33
respect_gg, подробнее...., не сбиает в каком случае ? берсерк тоже не сбивает приказ, но если его триггерно отдать, то сбивает, а тут надо у предмета да ещё и перезарядку запустить
26
Bergi_Bear:
как ты запустишь кд предмет?, в этом сама и соль же!
Вариант А - каст через руну ладно, тебе оно не нравится
Вариант Б - грёбаный амулет, который запускается с каста даммика
Вариант В - промутить с эксгумацией я на предметах не пробовал, но на юнитах норм, так что не даю 100%
Вариант Г - mh
и чисто кастомная адоптация от меня
Вариант Д - заменять предмет неактивной копией (примерно как у тебя), и отображать числовое КД предмета за счёт уменьшения на нём зарядов (вообще так можно сделать параллельное истечение КД на одинаковых предметах)
Да, заряды это такое себе... но! я делал дотовские транквиллы, которые отрубают от получения героем любого урона на 8 сек, и отображение по-секундного КД никак негативно не сказалось на визуале
33
Extremator, я в курсе что ты знаешь, и спрашивал respect_gg, , темболее ты описал всё то что я сам предложил в сообщениях выше, очень смешно, что ты мне в качестве ответа кидаешь, мои же предложения
28
виджет лайф > .405 ............ серьёзно?
Ну а то тут не так, хотя UnitAlive гораздо лучше.
26
PT153, то что есть проверка статус смерти юнита, а речь не о UnitAlive
Bergi_Bear:
я в курсе что ты знаешь, и спрашивал respect_gg
я чуть тупанул, мне показалось что это написал NazarPunk
28
то что есть проверка статус смерти юнита
Да какая разница, IsUnitType и GetWidgetLife в данной ситуации одинаковы, первая функция берёт 2 аргумента, а вторая требует сравнения с 0 или с .405, UnitAlive всё равно лучше обеих.
26
PT153:
Да какая разница, IsUnitType и GetWidgetLife в данной ситуации одинаковы, первая функция берёт 2 аргумента, а вторая требует сравнения с 0 или с .405, UnitAlive всё равно лучше обеих.
функция IsUnitAliveBJ возвращает ответ функции IsUnitDeadBJ с приставкой not
функция IsUnitDeadBJ возвращает - ( ХП юнита <= 0 )
используя GetUnitState(whichUnit, UNIT_STATE_LIFE)
ты же говорить - про эффективность числа 0.405 в том же сравнении
При этом есть такой факт, что ХП юнита может быть БОЛЬШЕ 1 ед., в тот момент времени когда юнит по факту является МЁРТВЫМ - в таком случае все ваши проверки вернут "да, юнит жив", хотя это будет не так.
Кажется фигня? а потом в карте появляется странный, но до невыносимости знакомый баг - при смерти из героя выпадают некоторые предметы (а то и все). Даже в той же DotA в своё время (имею ввиду время её актуальности до 2015 года, пока её обновляли) этот баг - Тараска и Даггер выпадали из героев, и поэтому руна-книжка всегда создавалась на базе игрока, а потом ему приходилось её подбирать...
30
Вот все функции для проверки жив ли юнит
function IsUnitAliveBJ takes unit whichUnit returns boolean
    return not IsUnitDeadBJ(whichUnit)
endfunction
function IsUnitDeadBJ takes unit whichUnit returns boolean
    return GetUnitState(whichUnit, UNIT_STATE_LIFE) <= 0
endfunction
function UnitAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0
endfunction
Так что их можно суммировать и написать мегафункцию
function IsUnitAlive(unit target) -> boolean {
    return GetWidgetLife(target) > 0.405 && !IsUnitType(target, UNIT_TYPE_DEAD) && GetUnitTypeId(target) != 0;
}
30
ScopteRectuS:
NazarPunk, UnitAlive - нативная функция же.
блин, по запаре не то скопривовал, хотел
native UnitAlive takes unit u returns boolean
Написал тест для проверки проверки
native UnitAlive takes unit u returns boolean
// !nocjass
//! zinc
library Start {

    unit U;
    
    function msg(string s, boolean b){
        string hp = R2S(GetWidgetLife(U));
        if (b) {BJDebugMsg(s + " - |cff00ff00Жив|r: |cff909090" + hp+"|r" ); }
        else { BJDebugMsg(s + " - |cffff0000Мёртв: |cff909090" + hp+"|r"); }
    }
    
    function IsUnitAlive(unit target) -> boolean {
        return GetWidgetLife(target) > 0.405 && !IsUnitType(target, UNIT_TYPE_DEAD) && GetUnitTypeId(target) != 0;
    }
    
    function test(string s){
        BJDebugMsg("|c55000099------"+s+"|r");
        msg("UnitAlive", UnitAlive(U));
        msg("IsUnitAliveBJ", IsUnitAliveBJ(U));
        msg("GetWidgetLife(U) > 0.405", GetWidgetLife(U) > 0.405);
        msg("IsUnitAlive",IsUnitAlive(U));
    }

    function onInit(){
        TimerStart(CreateTimer(), 0.01, false, function(){
            U = CreateUnit(Player(0), 'hfoo', GetStartLocationX(0), GetStartLocationY(0), GetRandomReal(0, 360));
            test("CreateUnit");
            KillUnit(U);
            test("KillUnit");
            SetWidgetLife(U, 30);
            test("SetWidgetLife(U, 30)");
            RemoveUnit(U);
            test("RemoveUnit(U)");
        });
        
    }
}
//! endzinc
// !endnocjass
Загруженные файлы
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.