27

» WarCraft 3 / Хеш-таблица против обуза глобальных массивных переменных

У обычных массивов от переменной, то там индекс не такой большой (от -8192 до 8192). Нельзя туда ни хэндлы всунуть, ни равкоды. Равкод к счастью можно заменить на тип переменную как тип юнита. А в хэш-таблицу все влезает, и норм. Обычные массивы неудобны еще тем, что там нельзя аттачить, приходится делать более сложные конструкции с пробегом цикла и проверками, чтобы найти нужный индекс. А вот в хэше можно сразу лепить аттач (по хэндлу юнита).
Различны способы хранения - (удобно когда массивов больше - удобно сделать сложную конструкцию). В более простых конструкциях этого не нужно.
xgm.guru/p/100/183113 массивы хэша
xgm.guru/p/100/183650 пробовал реализовать с помощью неких констант, когда не хватало ячеек
27

» WarCraft 3 / ID приказа при использовании предмета

Помню пробовал проверить стан с помощью событии (где условие GetIssuedOrderId() == 851973), но стан так и не получилось словить (только текущий можно)
ой сорри проверил только что, работает. условие GetIssuedOrderId() == 851973 работает
biridius, мб условие. у вас условием отличается.
27

» WarCraft 3 / ID приказа при использовании предмета

biridius, можно только текущий приказ узнать (есть спец. нативка GetUnitCurrentOrder), вот по событию не получится кажется найти по GetIssuedOrderId. В этот момент только получает приказ, самого состояния (стана) не достиг. Помню пробовал проверить стан с помощью событии (где условие GetIssuedOrderId() == 851973), но стан так и не получилось словить (только текущий можно)
27

» WarCraft 3 / Временное случайное событие

создаешь две целочисленные переменные (рандом и К), при касте в одном триггере рандомите случайное число (рандом), во втором триггере периодически прибавляете к переменной К.
27

» WarCraft 3 / Нужно отловить widget (memory hack)

quq_CCCP, можно настроить так, чтобы дерево выделялось)) в РО настраивается, но это значит у дерева будет видно полоска здоровья и круг. типа будет это как обычные железные ворота. если ты не знал. ладно. но мне кажется это дереву не нужно.
27

» WarCraft 3 / Нужно отловить widget (memory hack)

DracoL1ch, мб имеет в виде выделен игроком (зеленым/желтым/красным отображаются круги под ногами юнитов и мышка, а еще у юнитов отображается в интерфейсе отображаются морды - хотел сказать портреты лица главаря и отряды - иконки тех, кто выделен)? вот определить типа как с юнитами, там можно вычислить выделен юнит игроком или нет. А тут то widget (объект). Вроде итем и декорации, и все, есть что еще выделить можно в игре
27

» WarCraft 3 / Отлавливание области применения заклинания (тригерно)

это варкрафт? юзай поиск
вот карты
ставить им хп на макс (к примеру на максимум ) это даже в гуи есть такая функция как изменить здоровье декорации, а так же в разделе анимация, можно заставить дерево проигрывать анимацию роста....
чтобы было как в волне силы, нужен таймер + реальная переменная. Реальная переменная отвечает за радиус, есть функция выбора декорации в радиусе вокруг точки. С каждом секундой двигаешь точку и увеличиваешь радиус, и проверяешь.
здесь кажется конусные заклинания идут? это посложнее. можно еще с помощью треугольника проверять, лежит ли данная декорация в треугольнике xgm.guru/p/wc3/58159
27

» WarCraft 3 / Система покупки и продажи предмета

инициализация
закладывает в лавку
function Trig_PawnItem_Actions takes nothing returns nothing
    local unit market = gg_unit_nmrk_0009 //магазин
    local integer IdMarket = GetHandleId(market) //ид-хэндл магазина
    local item it = GetSoldItem() //итем
    local integer id = GetItemTypeId(it) //основной тип итема
    local integer ID //подменяющий тип итема, нужен для работ с рунами
    local integer count = LoadInteger(udg_Hash, IdMarket, udg_CountOfSlots) //кол-во занятых слотов
    local boolean busy_slot //занимает ли данный тип итема какую-нибудь ячейку итема
    local boolean sell_item = LoadBoolean(udg_Hash, IdMarket, udg_sell_item) //можно ли продавать в магазин
    local integer charges
    local integer count_charges
    local integer stock
    local integer max_stock
    local integer id1
    local integer MaxIT
    local boolean can_set = false
    local integer i
    local integer k = 0
    local boolean BBB
    local boolean XXX = true
    // Если является обычным предметов, связующий с руной. То можно заранее создать руну
    if ( id == 'wild' )then //амулет леса
        set ID = 'I007'
    elseif ( id == 'I001' )then //боевые когти
        set ID = 'I005'
    elseif ( id == 'I002' )then //туфли ловкости
        set ID = 'I006'
    elseif ( id == 'I000' )then //рецепт когти воина
        set ID = 'I004'
    else
        set ID = id
    endif
    set charges = GetItemCharges(it)
    set id1 = ( ID + udg_CountOfSlots ) //подзагружает или сохраняет логическую busy_slot
    set busy_slot = LoadBoolean(udg_Hash, IdMarket, id1) // занимает ли данный тип предмета магазин
    call BJDebugMsg( "|cFFFF5800закладываемый предмет в рынок |cFFFFDC00" + GetItemName(it) + "|r" ) 
    
    if (not busy_slot) then
        call BJDebugMsg( "данный предмет НЕ занимает место в магазине" )
    else
        call BJDebugMsg( "данный предмет занимает место в магазине" )
    endif
    
    
    
    if (count >= 0 and count <= 11) then // ЕСЛИ у магазина есть свободные ячейки, то ...
         
        if ( charges == 0 ) then // обычные итемы не имеют зарядов (равен нулю).
            set count_charges = 1 //Поэтому приравниваем к единице
        else
            set count_charges = charges // остальные итемы, имеющие заряды. у них приравнивают к зарядам
        endif
        call BJDebugMsg( "|cFFFFA500" + I2S(count_charges) + " - кол-во зарядов в предмете" + "|r" )
        
        
        // проверяем, данный тип у предмета есть в магазине или нет.
        if ( busy_slot ) then // Если есть, то выгружаем из хэша и складываем все
            // загружаем стэки из хэша (стэк - кол-во штук итемов в магазине)
            set stock = LoadInteger(udg_Hash, IdMarket, ID)
            call BJDebugMsg( "|cFF12FC40" + I2S(stock) + " - кол-во стэков из хэша" + "|r" )
            // складываем заряды и стэки в переменную max_stock
            set max_stock = ( count_charges + stock )
            call BJDebugMsg( "|cFFFFA500" + I2S(count_charges) + " кол-во зарядов Sold Item|r " + "+ " + "|cFF12FC40" + I2S(stock) + " кол-во стэков у предмета в магазине (из хэша)|r " + "= " + I2S(max_stock) )
            
            
            // сохраняем стэк в хэш
            call SaveInteger( udg_Hash, IdMarket, ID, max_stock)
            set MaxIT = max_stock
            set can_set = true
            
        elseif ( (not busy_slot) and (count < 11) ) then //Иначе, если нет в магазине, то создаем новый (ничего не выгружая).
        
                // кол-во занятых ячеек в магазине стало больше на одну
                set count = ( count + 1 )
                // сохраняем кол-во занятых ячеек
                call SaveInteger( udg_Hash, IdMarket, udg_CountOfSlots, count )

                set i = 1
                call BJDebugMsg("начало цЫкла ")
                loop
                    exitwhen i > 12
                    set udg_ITEM[i] = LoadInteger(udg_Hash, IdMarket, udg_XXX + i )
                    set BBB = LoadBoolean(udg_Hash, IdMarket, udg_CountOfSlots + udg_ITEM[i])
                    if udg_ITEM[i] != id and udg_ITEM[i]>= 0 and (not BBB) and XXX then
                        set XXX = false
                        call SaveInteger( udg_Hash, IdMarket, udg_XXX + i, ID )
                        call BJDebugMsg("сохранка ")
                        
                    endif
                    set i = i + 1
                endloop
                
                
                call BJDebugMsg("|cFF00FFFF" + "Кол-во занятых слотов стало больше, теперь их всего " + I2S(count) + "|r")
                // сохранить кол-во стэков предмета в магазине
                call SaveInteger( udg_Hash, IdMarket, ID, count_charges )
                set MaxIT = count_charges
                set can_set = true
                call BJDebugMsg( "|cFFFFA500" + I2S(count_charges) + " кол-во зарядов Sold Item|r ")
                // сохраняем то, что юнит обладает данным типом
                call SaveBoolean( udg_Hash, IdMarket, id1, true )
                
                
                
                set i = 1
                set k = 0
                loop
                    exitwhen i > 12
                    set udg_ITEM[i] = LoadInteger(udg_Hash, IdMarket, udg_XXX + i )
                    set BBB = LoadBoolean(udg_Hash, IdMarket, udg_CountOfSlots + udg_ITEM[i])
                    if BBB then//
                        set k = k + 1
                    endif
                    set i = i + 1
                endloop
                call BJDebugMsg("КОЛ_ВО ПРЕДМЕТОВ " + I2S(k))
                //сохраняем какой-тип сохраняем
                
                
                
                
                // идет еще следующая проверка. Проверяет, стало ли занятых ячеек равно 11. Если да. то нужно ограничить
                if ( count == 11 ) then
                    // если все ячейки заполнены. то удаляем способность продажа предметов, и никто больше не сможет продавать
                    call BJDebugMsg( "способность удалена, теперь нельзя продавать предметы" )
                    call UnitRemoveAbility( market, 'Apit')
                    // запоминаем, что способность удалена
                    call SaveBoolean( udg_Hash, IdMarket, udg_sell_item, true )
                endif
                
        
                
        endif
        

        
        if (can_set) then
            // Продажа=Появление
            call BJDebugMsg( "может продавать" )
            call AddItemToStock( market, ID, MaxIT, MaxIT )
        endif
    
    
    
    elseif (count == 11 and (not busy_slot)) then
        //call UnitRemoveAbility( market, 'Apit')
        //call UnitAddAbility( market, 'Apit')
    endif
    set market = null
    set it = null
endfunction

//===========================================================================
function InitTrig_PawnItem takes nothing returns nothing
    set gg_trg_PawnItem = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_PawnItem, EVENT_PLAYER_UNIT_PAWN_ITEM )
    call TriggerAddAction( gg_trg_PawnItem, function Trig_PawnItem_Actions )
endfunction
при инициализации устанавливаем кол-во зарядов
function Trig_data_Actions takes nothing returns nothing
    local unit market = gg_unit_nmrk_0009 //магазин
    call TriggerSleepAction( 2 )
    call SaveInteger(udg_Hash, udg_kkk, 'I007', 1) //амулет леса (руна)
    call SaveInteger(udg_Hash, udg_kkk, 'I001', 1) //Боевые когти (руна)
    call SaveInteger(udg_Hash, udg_kkk, 'I002', 1) //Туфли логкости (руна)
    call SaveInteger(udg_Hash, udg_kkk, 'I003', 1) //когти воина (руна)
    call SaveInteger(udg_Hash, udg_kkk, 'I000', 1) //рецепт когти воина (руна)
    call SaveInteger(udg_Hash, udg_kkk, 'pghe', 1) //целебное зелье
    call SaveInteger(udg_Hash, udg_kkk, 'rde3', 1) //кольцо защиты (+4)
    call SaveInteger(udg_Hash, udg_kkk, 'afac', 1) //флейта меткости
    call SaveInteger(udg_Hash, udg_kkk, 'kpin', 1) //флейта прозрения
    call SaveInteger(udg_Hash, udg_kkk, 'odef', 1) //сфера тьмы
    call SaveInteger(udg_Hash, udg_kkk, 'evtl', 1) //талисман защиты
    call SaveInteger(udg_Hash, udg_kkk, 'bspd', 1) //сапоги - сккороходы
    call SaveInteger(udg_Hash, udg_kkk, 'bgst', 1) //пос богатыря
    call SaveInteger(udg_Hash, udg_kkk, 'gcel', 1) //перчатки скорости
    call SaveInteger(udg_Hash, udg_kkk, 'lhst', 1) //рог ветров
    call SaveInteger(udg_Hash, udg_kkk, 'rst1', 1) //руковица огра
    call SaveInteger(udg_Hash, udg_kkk, 'brac', 1) //рунные браслеты
    call SaveInteger(udg_Hash, udg_kkk, 'prvt', 1) //талисман здоровья
    call SaveInteger(udg_Hash, udg_kkk, 'clfm', 1) //огненный плащ
    call SaveInteger(udg_Hash, udg_kkk, 'ciri', 1) //одеяние мага
    
    
    
    
    set market = null
endfunction

//===========================================================================
function InitTrig_data takes nothing returns nothing
    set gg_trg_data = CreateTrigger(  )
    call TriggerAddAction( gg_trg_data, function Trig_data_Actions )
endfunction
продает из лавки
function Trig_SellItem_Actions takes nothing returns nothing
    local unit market = gg_unit_nmrk_0009
    local integer Id = GetHandleId(market) // номер хэндла магазина
    local item it = GetSoldItem() //итем
    local integer id = GetItemTypeId(it) //тип итема
    local integer count = LoadInteger(udg_Hash, Id, udg_CountOfSlots) //кол-во занятых слотов
    local integer id1 = (id + udg_CountOfSlots)
    local boolean busy_slot = LoadBoolean(udg_Hash, Id, id1) // занимает ли данный тип предмета магазин
    local integer charges_item = LoadInteger(udg_Hash, udg_kkk, id)
    local integer stock = LoadInteger(udg_Hash, Id, id)
    local integer min_stock
    local boolean sell_item = LoadBoolean(udg_Hash, Id, udg_sell_item) //можно ли продавать в магазин
    local integer min_count
    local integer i = 1
    local integer o
    local integer s
    
    local integer ID
    local integer jd
    local boolean bb =false
    call BJDebugMsg( "|cFFFF5800Купленный предмет в магазине |cFFFFDC00" + GetItemName(it) + "|r" ) 
    call BJDebugMsg( "|cFF12FC40" + I2S(stock) + " - кол-во стэков из хэша" )
    call BJDebugMsg( "|cFFFFA500" + I2S(charges_item) + " - кол-во отнимаемых зарядов у итема (загружается из базы данных типа итема)" + "|r" )
    // вычитаем, тут еще проверку надо что если зарядов больше стэков
    set min_stock = stock - charges_item
    call BJDebugMsg( "|cFF12FC40" + I2S(stock) + " кол-во стэков у предмета в магазине|r" + " - " + "|cFFFFA500" + I2S(charges_item) + " кол-во отнимаемых зарядов Sold Item (указывается в базе данных)|r " +  " = " + I2S(min_stock))


    if ( busy_slot and count > 0 and count <= 11 ) then
    // сохраняем кол-во стэков
    call SaveInteger( udg_Hash, Id, id, min_stock )
    
        if (min_stock==0) then //если кол-во стэков стало равно ноль, то удаляем итем
            //ВНИЗУ ИДЕТ ПОЛНОЕ вычищение ИТЕМА из магазина, перерасчет кол-во занимаемых слотов
            set min_count = count - 1
            set bb = true
            call BJDebugMsg( "стэков стало ноль" )
            
            
            
            
            
            
            
            
            call BJDebugMsg( "|cFF00FFFF" + "поубавилось, было " + I2S(count) + ", но стало" + I2S(min_count)+"кол-во занятых ячеек в магазине|r" )
            // сохраняем кол-во занимаемых ячеек
            call SaveInteger( udg_Hash, Id, udg_CountOfSlots, min_count )
            

            // удаляем итем из магазина
            call RemoveItemFromStock( market, id )
            // запоминаем в хэш что данного типа предмета больше нет
            call SaveBoolean( udg_Hash, Id, id1, false )
            
            
            
            
            
            
            
            
            
            // проверяем ячейки магазина
            if ( count == 11 and min_count == 10 ) then // если ячейка освободилась, то добавляем способность
            
                call BJDebugMsg( "Свободных слотов в магазине было 11, стало 10. Ячейка освободилась" )
                if ( sell_item ) then
                    call UnitAddAbility( market,'Apit' )
                    //call TriggerSleepAction( 0.00 )
                    call BJDebugMsg( "НЕЛЬЗЯ БЫЛО ПРОДАВАТЬ - теперь МОЖНО" )
                    // запоминаем, что способность больше не удалена
                    call SaveBoolean( udg_Hash, Id, udg_sell_item, false )
                    
                endif
            endif
        elseif (min_stock > 0) then

            // сохраняем кол-во занимаемых ячеек
            call BJDebugMsg( "итог " + I2S(min_stock) )

            call AddItemToStock( market, id, min_stock, min_stock )
        endif
    endif
    
    loop
        exitwhen i>12
        set o = udg_XXX + i //подключ хэш-таблицы
        set udg_ITEM[i] = LoadInteger( udg_Hash, Id, o ) //загружаем тип итема в глобалку
        set jd = udg_ITEM[i]
        
        if (udg_ITEM[i] == id and bb) or (udg_ITEM[i] == 0) then //проверяем тип итема (загружаемый тип итема не равно пустому слоту == 0) или тип итема не равно купленному типу
            call SaveInteger( udg_Hash, Id, o, 0 ) //сохраняем тип итема в данной ячейке (ячейка нумеруется номером)
            set udg_ITEM[i] = 0
        elseif (udg_ITEM[i] > 0) then

            set s = LoadInteger( udg_Hash, Id, udg_ITEM[i] ) //кол-во стэков
            call AddItemToStock( market, udg_ITEM[i], s, s )
        endif
        
        
        
        set i = i + 1
    endloop
    
    
    set market = null
    set it = null
endfunction

//===========================================================================
function InitTrig_SellItem takes nothing returns nothing
    set gg_trg_SellItem = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_SellItem, EVENT_PLAYER_UNIT_SELL_ITEM )
    call TriggerAddAction( gg_trg_SellItem, function Trig_SellItem_Actions )
endfunction
Загруженные файлы
27

» WarCraft 3 / Как сделать чтоб когда танк делает выстрелснаряд летел прямо?

Принятый ответ
вот, делал не я.
  • игнорируют высоту рельефа и не скачут при резкой смене возвышенности, и летят прямо. такое бывает. надо смотреть как сделано в картах.
  • есть столкновения снаряда об рельеф, если движению снаряда препятствует рельеф (горы, скалы и др.)
  • также тут есть проверки, чтобы снаряд не вылетал за карту. (он взрывается на окраине карты)
  • еще можно осуществить выстрелы вверх, то есть запустить прямо по воздушным целям
27

» WarCraft 3 / Файлы и язык программирования jass

DracoL1ch, а за что за программа? UltraEdit? и интересно на видео автор так быстро пишет, это ему прога помогает?
27

» WarCraft 3 / Не работает изменение кнопки приказов.

Maniac_91, ааааа вот ступил я)) я вот хоткей поменял то, а текст оставил блин. И думал, что у меня не меняется текст, а говорю тебе у меня хоткей не меняется).
27

» WarCraft 3 / Не работает изменение кнопки приказов.

Maniac_91, не помогает, короче не знаю что, скорее из-за самого варкрафта
Загруженные файлы
27

» WarCraft 3 / Не работает изменение кнопки приказов.

Maniac_91, нее. у меня что-то не работает. все текстовики из разных архивов вытаскивал, изменял, сохранял на рабочем столе, вставлял в карту. короче все текстовики не работают, а твой норм работает
мб быть
27

» WarCraft 3 / Не работает изменение кнопки приказов.

Maniac_91, я просто взял из первого попавшегося верхнего архива. war3.mpq. там несколько архивов. у меня также 1.26. мб нужно было из других архивов брать текстовик и редактировать
27

» WarCraft 3 / Не работает изменение кнопки приказов.

Maniac_91, блин у тебя работает)
но у меня в карте что-то не то, что не так то? получается дело в текстовике, взял твой и вставил, норм заменил. А мой не робит. хз
Загруженные файлы
27

» WarCraft 3 / Не работает изменение кнопки приказов.

пробовал сейчас, действительно не работает. Не всегда работает как хотелось, видимо вшито в движке
27

» WarCraft 3 / Для чего нужны эти строки?

Принятый ответ
все верно подметили выше. редактировать приказы мы не можем =(( и поэтому бесполезны. Попробуй сделать две разные способности, сделанные на одной основе, и дать герою. Попробуй активировать одну из них, и, если активируешь, то в перезарядку уходят оба скила. Кто-то скажет, что дело в приказах. Все верно. Но если их поменять (эти строчки, что ты перечислил, то все равно не меняются) Даже, если в редакторе эти стандартные строчки поменять, то в игре этот приказ никак не меняется.
Они доступны у определенных скилов, вот строчки (используется / не используется) доступны только автокастовым способностям
подробное описание
Порядок строк: Включён - это у всех активных способностей.
Порядок строк: Выключен - это обычно у способностей двойного действия (типа включил - выключил). Строчка врубает приказ на отключение способности. Есть это у двойных способностей наподобие щита у пехотинца (укрыться щитом), и у ведьмака (магическая защита).
Порядок строк: Используется / Не используется - эти две строчки связаны с автокастовыми способностями.
это все можно узнать, лишь сравнив с другими абилками
Порядок строк: Изучить - такой строчки кажись не видел, не существует
xgm.guru/forum/showthread.php?t=5335 поиск в помощь, хотя мне кажется неправильно пояснено автором, что делают эти строчки, но ладно.
27

» WarCraft 3 / Пути

темы похожие нашел
везде советуют рассчитать путь. кажется нереальным это сделать. это в высшем программировании
раскрыть
native IsTerrainPathable takes real x, real y, pathingtype t returns boolean
кстати когда то делал нечто похожее через нативку выше, делал своих ботов ИИ, рассчитывал пути строительства. Вокруг ратуши рассчитывал как и что строить, вроде прикольно получилось, но с ИИ дальше дело не пошло, вышло очень громозким (нужно было бд писать, какой радиус/площадь у каждой стройки и зазор между зданиями (и радиус зачастую не верно определял, поэтому не ставил постройку раб), и в какой последовательности строить), а также долго искало место для постройки, и даже зацикливалось с вылетом игры =((
а вот искать маршрут, я не понимать как составлять алгоритм поиска к ближайшей точке
27

» WarCraft 3 / Пути

Vampir_kolik, упс. ошибся. не совсем верное решение. Там короче если отдать приказ он все равно побежит туда (то есть почти в большинстве случаев (99%) это будет истина), и бежит пока не упрется в преграду. Тогда он останавливается и все.
27

» WarCraft 3 / Пути

через приказ можно проверить. нативки приказа возвращают boolean. Если туда можно пройти, то вернут истину true, если нельзя то ложь false. Создай dummy и проверь, попробуй отдать приказ.
27

» WarCraft 3 / Сварка предметов при использовании рун пустышек

Принятый ответ
раскрыть
  1. Существуют оригинал и их копия - руна. Руна пропадает при ее подборе или покупки.
  2. В магазине и на земле лежат руны.
  3. Каждый раз когда дропают с инвентаря оригинал, то пикают все итемы на карте и подменяют на руны. В нее можно передавать заряды. Однако, происходит это не сразу. Но этого можно не заметить
  4. При получении руны сама руна исчезает. Короче можно узнать тип руны (ид). Проверяем различные связки скрещивания итемов (циклом пробегаем, какие итемы есть в инвентаре героя). Есть не идет одна связка, то следующую связку проверяем, если и эта не идет, то следующую. И так далее, если все связки не прокатили, то возвращаем оригинал. Если это зарядовые итемы (бутылочки всякие), то можно складывать. Кстати сам манипулирующий итем удаляем
  5. есть еще такие хитрости когда связка должна иметь две одинаковые пары носков и одну пару ботинков. Нужно циклом перечитывать сколько одинаковых итемов лежит в инвентаре
  6. есть в гуи проверка, что герои имеет итем определенного типа. Но некуда не годится это. Во-первых, тут утечка - необнуленная локалка. И во-вторых, это пункт 5, то что выше (когда нужно проверить, есть ли два одинаковых итема. Это делается циклом).
то что скинул, это просто пример для новичков. когда то сам с этого начинал
27

» WarCraft 3 / Массовый временный таймстоп для всех в игре, кроме кастера

можно одним даймиком на всех юнитов кастануть через for group (а вот на FirstOfGroup через цикл не получится на всех, если я не ошибаюсь)
xgm.guru/forum/showthread.php?t=48211 старая тема, когда хотел кастануть на всех
xgm.guru/forum/showthread.php?t=9494 тфу не то скинул
попробуй, не знаю,заюзать новый ретурн бан. там можно станы давать
есть смысл пустить корни xgm.guru/forum/showthread.php?t=56893
замедлить скорость атаки и передвижения, добавляя отриц. значения абилкам
xgm.guru/forum/showthread.php?t=38801 нашел про пруф про стан, надо будет попробовать
а если есть иммунитет от магии, то удаляй способности и заново добавляй