Библиотека, позволяющая отменять входящий урон.
код
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
Установка
- Скачать .j файл и переместить в Директория-JNGP/jass.
- В коде карты прописать импорт библиотеки.
//! import "NegateDamageLibrary.j"
- Создать способность (далее NegateDamageAbil), которая увеличивает максимальное здоровье юнитов. Рекомендуется создать способность на основе Item Life Bonus [AIlf] с увеличением здоровья на 1 миллион или больше.
- Указать равкод способности и значение увеличения здоровья в константах по шаблону ниже.
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, которая даёт ему щиты. Щиты поглощают весь входящий урон, пока не израсходуются.
У пехотинца есть способность 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
Исправлены критические ошибки.
Ред. GetLocalPlayer
Но!
Но мы вероятно можем контролировать момент, когда мы добавляем макс. хп. Варкрафт ведь линеен, у него нет многопоточности, он не порождает параллельных процессов. Это означает что все триггеры на получение урона юнитом, срабатывают последовательно. Но под влиянием каких правил выстраивается последовательность исполнения триггеров? В порядке назначения им событий? Или в порядке создания триггеров? Зависит ли очередь от величины числового значения хэндла? В порядке регистрации собития (TriggerRegister...Event)? Это очередь или стек?
Ред. PT153
Ред. GetLocalPlayer
Тем не менее, на данном этапе можно намутить хотя бы это
Но это прокатило бы если бы хуки вызывали хук-функцию после оригинальной, а не перед.
Ред. PT153
И хуки с предупреждением в дебаг моде на функции GetUnitState, GetUnitStateSwap, GetUnitStatePercent, GetUnitLife все таки нужны.
Ред. KaneThaumaturge
Ред. PT153