Добавлен , опубликован
Способ реализации:
Версия Warcraft:
Библиотека, позволяющая отменять входящий урон.
код
library NegateDamageLib
globals
    private constant group Group = CreateGroup()
    private constant timer Timer = CreateTimer()

    public keyword MaxLifeBonusAbility
    public keyword MaxLifeBonus
endglobals

native UnitAlive takes unit id returns boolean

function GetUnitMaxLife takes unit u returns real
    return GetUnitState(u, UNIT_STATE_MAX_LIFE) - GetUnitAbilityLevel(u, MaxLifeBonusAbility) * MaxLifeBonus
endfunction

private function ProcessUnits takes nothing returns nothing
    local unit u
    local real life2set

    loop
        set u = FirstOfGroup(Group)
        exitwhen u == null
        call GroupRemoveUnit(Group, u)

        if UnitAlive(u) then
            set life2set = GetWidgetLife(u)
            call UnitRemoveAbility(u, MaxLifeBonusAbility)
            call SetWidgetLife(u, life2set)
        else
            call UnitRemoveAbility(u, MaxLifeBonusAbility)
        endif
    endloop
endfunction

function NegateDamage takes unit u, real negated returns nothing
    local real life2set = GetWidgetLife(u) + negated
    local boolean add_ability = life2set > GetUnitState(u, UNIT_STATE_MAX_LIFE)

    if add_ability then
        call GroupAddUnit(Group, u)
        call UnitAddAbility(u, MaxLifeBonusAbility)
    endif

    call SetWidgetLife(u, life2set)

    if add_ability then
        call TimerStart(Timer, 0., false, function ProcessUnits)
    endif
endfunction

endlibrary

Установка

  1. Скачать .j файл и переместить в Директория-JNGP/jass.
  2. В коде карты прописать импорт библиотеки.
//! import "NegateDamageLibrary.j"
  1. Создать способность (далее NegateDamageAbil), которая увеличивает максимальное здоровье юнитов. Рекомендуется создать способность на основе Item Life Bonus [AIlf] с увеличением здоровья на 1 миллион или больше.
  2. Указать равкод способности и значение увеличения здоровья в константах по шаблону ниже.
globals
    constant integer NegateDamageLib_MaxLifeBonusAbility = 'A000'
    constant integer NegateDamageLib_MaxLifeBonus = 1000000
endglobals

Использование

NegateDamage
call NegateDamage(damaged_unit, damage_to_negate)
Отменяет damage_to_negate для damaged_unit. damage_to_negate должно быть больше 0. Если это значение больше входящего урона, то юнит будет вылечен на разницу этих значений. Если вызывать функцию не в триггере получения урона, то damaged_unit будет вылечен на damage_to_negate.
Отмена может не произойти в следующих случаях:
  • Входящий урон больше, чем бонус здоровья способности NegateDamageAbil.
  • У юнита здоровья меньше чем 1.
GetUnitMaxLife
set max_life = GetUnitMaxLife(any_unit)
Возвращает максимальное здоровье any_unit без учёта бонуса от NegateDamageAbil.

Особенности

Функция NegateDamage меняет текущее и максимальное здоровье юнита во время вызова и через некоторое время ещё раз:
  • Триггеры с событием Unit - Life (TriggerRegisterUnitLifeEvent) могут срабатывать во время изменений здоровья.
  • Чтобы узнавать максимальное здоровье без учёта изменений от NegateDamage, используйте функцию GetUnitMaxLife.

Примеры

Имунные рабочие

Карта
Рабочие игнорируют любой урон до миллиона включительно. Урон более миллиона может убить, а может и не убить.

Щит

Карта
У пехотинца есть способность Shield, которая даёт ему щиты. Щиты поглощают весь входящий урон, пока не израсходуются.

Обновления

08.12.2024
  • Настраиваемые константы (MaxLifeBonusAbility и MaxLifeBonus) теперь можно определить вне библиотеки.
    • Это позволяет импортировать библиотеку из файла, а не копировать её в код карты.
    • В связи с этим изменён способ установки и настройки.
  • Тестовые карты были обновлены для соответствия изменениям выше.
01.12.2024
  • Таймер запускается, только если способность NegateDamageAbil была добавлена.
  • Тестовые карты были обновлены для соответствия изменениям выше.
  • В карте NegateDamage-shield занулены поля Art - Animation - Cast Backswing и Art - Animation - Cast Point у пехотинца.
27.01.2022
  • Теперь способность добавляется в случаях, если сумма текущего здоровья и отменяемого урона больше максимального запаса здоровья.
  • GetUnitMaxHealth переименована в GetUnitMaxLife.
  • Тестовые карты были обновлены для соответствия изменениям выше.
25.12.2021
  • Убрано требование "библиотеки" AINativesLib, так как тот ресурс был обновлён.
  • Определение UnitAlive было добавлено в код самой библиотеки.
  • Обновлены тестовые карты дабы соответствовать изменениям выше.
23.03.2021
  • Добавлена функция GetUnitMaxHealth.
  • Некоторые константы стали публичными.
  • Добавлена ещё одна карта-пример.
21.03.2021 - 3
Полная переработка библиотеки:
  • Делает всё тоже самое, но лучше. Например, теперь регенерация здоровья верно работают у юнитов, которые игнорируют весь входящий урон и находятся под непрерывным огнём.
  • Убрана целая куча настроек и требований.
21.03.2021 - 2
  • В требования добавлена AI natives library.
  • Изменена проверка того, что юнит жив.
21.03.2021 - 1
  • Обновлён способ отключения других триггеров, отслеживающих урон.
  • Обновлена карта-пример.
  • Улучшена обработка случая, когда юнит умирает от полученного урона.
16.03.2021
Исправлены критические ошибки.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
28
Vlod, потому что это короче, говорят, что ещё и быстрее, а суть та же, что и у UnitState для жизни.
15
Нипанаятна.
С одной стороны, юниту необходимо установить его текущее здоровье в момент выдачи способности с дополнительным хп, поскольку, при увеличении максимального запаса здоровья, процент текущего запаса здоровья сохраняется, что изменяет его численное количество (или нет?).
С другой стороны, отхиливать юнита нужно в момент нанесения урона. Если делать это в таймере с нулевой задержкой, то в момент исполнения кода таймера юнит уже может быть мертв от того самого урона, от которого его полагалось отлечить.
8
С другой стороны, отхиливать юнита нужно в момент нанесения урона. Если делать это в таймере с нулевой задержкой, то в момент исполнения кода таймера юнит уже может быть мертв от того самого урона, от которого его полагалось отлечить.
Поэтому абилка с хп и добавляется. Всегда так делали на старых патчах
15
Поэтому абилка с хп и добавляется
Речь не про абилку а про отхил. Про то что отхиливать нужно в момент получения урона.
28
GetLocalPlayer, когда срабатывает событие, никакого урона нет. Он будет нанесён, когда триггер завершится. Если в триггере есть пауза, то когда она начнёт выполняться.

А, я понял, о чём речь.

Пока снял с публикации.
15
Теперь не ясно назначение функции HealUnits.
Технически, мы даем способность с дополнительным здоровьем только для того чтобы мы могли исцелить юнита, в случае, если необходимое исцеление превышает его максимальный запас здоровья. Следовательно, все, что нам нужно сделать по истечению таймера, это отнять у юнита эту способность. Нас даже не беспокоит, умер ли юнит на тот момент, нам нужно только отнять способность и установить его текущее здоровье равное здоровью до удаления способности, что-то вроде этого
Код
local unit u
local real currentHealth
loop
    set u = FirstOfGroup(...)
exithwen u == null
    set currentHealth = GetWidgetLife(u)
    call UnitRemoveAbiity(...)
    call SetWidgetLife(u, currentHealth)
    call GroupRemoveUnit(...)
endloop
28
установить его текущее здоровье равное здоровью до удаления способности
Достаточно запустить тестовую карту и убедиться, что так работать не будет.

Кратко говоря - во время выполнения функции у юнита может быть ~миллион хп, после удаления способности это превратится в 100% его нормального здоровья. А до всех манипуляций у юнита было 3 хп. Это хорошо видно в тестовой карте, нужно рабочего вниз увести.
28
Обновил проверку того, что юнит жив, заменив на более надёжную.
15
во время выполнения функции у юнита может быть миллион хп
Это откуда они у него возьмутся.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.