Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
Zinc
Тип:
Способность
Версия Warcraft:
1.26+

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

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
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
26
5 лет назад
0
PT153, то что есть проверка статус смерти юнита, а речь не о UnitAlive
Bergi_Bear:
я в курсе что ты знаешь, и спрашивал respect_gg
я чуть тупанул, мне показалось что это написал NazarPunk
0
28
5 лет назад
0
то что есть проверка статус смерти юнита
Да какая разница, IsUnitType и GetWidgetLife в данной ситуации одинаковы, первая функция берёт 2 аргумента, а вторая требует сравнения с 0 или с .405, UnitAlive всё равно лучше обеих.
0
26
5 лет назад
Отредактирован Extremator
0
PT153:
Да какая разница, IsUnitType и GetWidgetLife в данной ситуации одинаковы, первая функция берёт 2 аргумента, а вторая требует сравнения с 0 или с .405, UnitAlive всё равно лучше обеих.
функция IsUnitAliveBJ возвращает ответ функции IsUnitDeadBJ с приставкой not
функция IsUnitDeadBJ возвращает - ( ХП юнита <= 0 )
используя GetUnitState(whichUnit, UNIT_STATE_LIFE)
ты же говорить - про эффективность числа 0.405 в том же сравнении
При этом есть такой факт, что ХП юнита может быть БОЛЬШЕ 1 ед., в тот момент времени когда юнит по факту является МЁРТВЫМ - в таком случае все ваши проверки вернут "да, юнит жив", хотя это будет не так.
Кажется фигня? а потом в карте появляется странный, но до невыносимости знакомый баг - при смерти из героя выпадают некоторые предметы (а то и все). Даже в той же DotA в своё время (имею ввиду время её актуальности до 2015 года, пока её обновляли) этот баг - Тараска и Даггер выпадали из героев, и поэтому руна-книжка всегда создавалась на базе игрока, а потом ему приходилось её подбирать...
0
29
5 лет назад
0
Вот все функции для проверки жив ли юнит
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;
}
0
21
5 лет назад
0
NazarPunk, UnitAlive - нативная функция же.
0
29
5 лет назад
0
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
Загруженные файлы
0
28
5 лет назад
Отредактирован PT153
0
При этом есть такой факт, что ХП юнита может быть БОЛЬШЕ 1 ед., в тот момент времени когда юнит по факту является МЁРТВЫМ
Это не так, юнит умирает только если хп меньше 0.405, доказанный тестами факт. Такие приколы возникают только в момент получения урона, ведь урон ещё не был нанесён, потому и хп больше 1.
функция IsUnitAliveBJ возвращает ответ функции IsUnitDeadBJ с приставкой not
функция IsUnitDeadBJ возвращает - ( ХП юнита <= 0 )
используя GetUnitState(whichUnit, UNIT_STATE_LIFE)
ты же говорить - про эффективность числа 0.405 в том же сравнении
И к чему это? Тут кто-то говорил про использование этих функций? Зачем их вообще их использовать, если есть IsUnitType, GetWidgetLife и UnitAlive, которые ТОЧНО лучше этих BJ?

Так что их можно суммировать и написать мегафункцию
Тоже самое делает UnitAlive.

Вот нормальные функции на все случаи жизни.
раскрыть
UnitDead и UnitIsAlive определённо сомнительные функции.
native UnitAlive takes unit id returns boolean

function UnitDead takes unit u returns boolean
    return not UnitAlive(u)  // returns true, if unit does not exist.
endfunction

function UnitExists takes unit u returns boolean
    return GetUnitTypeId(u) != 0
endfunction

function UnitDoesNotExist takes unit u returns boolean
    return GetUnitTypeId(u) == 0
endfunction

function UnitIsAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction

function UnitIsDead takes unit u returns boolean
    return IsUnitType(u, UNIT_TYPE_DEAD)  // returns false, if unit does not exist.
endfunction
4
16
5 лет назад
4
UnitAlive лучше всех:
если юнита не существует, его хп ==0, но IsUnitType(DEAD)==false (потому что юнита нет)
если юнит мертв, но его хп поднялись, то хп >0 при UnitType(DEAD) == true
и UnitAlive работает четко во всех этих ситуациях
0
29
5 лет назад
0
и UnitAlive работает четко во всех этих ситуациях
Хорошо, что объявлять нативки можно по несколько раз, и ненужно заботится о redeclared.
0
26
5 лет назад
Отредактирован Extremator
0
PT153:
Это не так, юнит умирает только если хп меньше 0.405, доказанный тестами факт.
Речь о том что юнит мёртв, а игра сообщает обратное. И это так.
PT153:
И к чему это? Тут кто-то говорил про использование этих функций? Зачем их вообще их использовать, если есть IsUnitType, GetWidgetLife и UnitAlive, которые ТОЧНО лучше этих BJ?
Так ты и написал про UnitAlive, а т.к. в 1.26 нет функции UnitAlive, то за неё было принято IsUnitAliveBJ, т.к. является единственно подходящим по контексту (в заголовке указана именно 1.26 версия). Ты ничего не путаешь? Или ты специально вводишь всех в заблуждение?
0
29
5 лет назад
0
а т.к. в 1.26 нет функции UnitAlive
Как это нету?
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.