Добавлен , опубликован
Способ реализации:
Версия 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
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
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
Загруженные файлы
28
При этом есть такой факт, что ХП юнита может быть БОЛЬШЕ 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
16
UnitAlive лучше всех:
если юнита не существует, его хп ==0, но IsUnitType(DEAD)==false (потому что юнита нет)
если юнит мертв, но его хп поднялись, то хп >0 при UnitType(DEAD) == true
и UnitAlive работает четко во всех этих ситуациях
30
и UnitAlive работает четко во всех этих ситуациях
Хорошо, что объявлять нативки можно по несколько раз, и ненужно заботится о redeclared.
26
PT153:
Это не так, юнит умирает только если хп меньше 0.405, доказанный тестами факт.
Речь о том что юнит мёртв, а игра сообщает обратное. И это так.
PT153:
И к чему это? Тут кто-то говорил про использование этих функций? Зачем их вообще их использовать, если есть IsUnitType, GetWidgetLife и UnitAlive, которые ТОЧНО лучше этих BJ?
Так ты и написал про UnitAlive, а т.к. в 1.26 нет функции UnitAlive, то за неё было принято IsUnitAliveBJ, т.к. является единственно подходящим по контексту (в заголовке указана именно 1.26 версия). Ты ничего не путаешь? Или ты специально вводишь всех в заблуждение?
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.