Добавлен , опубликован
Предназначение:
Способ реализации:
Версия Warcraft:
Библиотека, добавляющая возможность вычислять текущую броню юнита со всеми текущими бонусами.

Установка

  1. Установить Math library и Negate Damage library.
  2. Скачать .j файл и переместить в Директория-JNGP/jass.
  3. В коде карты прописать импорт библиотеки.
//! import "GetUnitArmorLibrary.j"
  1. В коде карты определить константы для библиотеки:
globals
    constant integer GetUnitArmorLib_RegisteredPurgeThreshold = 100
    constant real GetUnitArmorLib_ArmorDamageReductionMultiplier = 0.06
    constant real GetUnitArmorLib_DamageAmount = 10000.
endglobals
Константы означают следующее:
  • RegisteredPurgeThreshold - указывает периодичность очистки группы с зарегистрированными юнитами. Рекомендуется установить значение на 100, то есть каждые 100 новых регистраций группа будет пересоздаваться.
  • ArmorDamageReductionMultiplier - значение игровой константы DefenseArmor (англ. Combat - Armor Damage Reduction Multiplier).
  • DamageAmount - урон, наносимый для вычисления брони. Данная константа должна соответствовать неравенству ниже для корректной работы библиотеки. Для большинства случаев 10000 подойдёт.
неравенство
1 / (min_damage_type_factor * min_etherial_factor * (1 - (max_armor * armor_factor) / (1 + max_armor * armor_factor))) < DamageAmount < max_life_bonus / (max_damage_type_factor * max_etherial_factor * (2 - (1 - armor_factor) ^ (-min_armor)))
Где:
  • min_damage_type_factor и max_damage_type_factor - минимальное и максимальное значения среди ненулевых значений из игровых констант типа DamageBonus.... По умолчанию 0.05 и 2.00 соответственно.
  • min_etherial_factor и max_etherial_factor - минимальное и максимальное значения среди ненулевых значений из игровой константы EtherialDamageBonus. По умолчанию оба значения равны 1.66.
  • armor_factor - значение игровой константы DefenseArmor. По умолчанию 0.06.
  • max_life_bonus - значение константы MaxLifeBonus для библиотеки NegateDamageLib.
  • min_armor и max_armor - минимальное и максимальное возможные значения брони в вашей карте. Считать min_armor как 0, если негативных значений брони в карте не предвидится.
Неравенство выглядит так, если использовать значения по умолчанию для игровых констант:
12.5 /  (1 - (max_armor * 0.06) / (1 + max_armor * 0.06)) < DamageAmount < max_life_bonus / (3.32 * (2 - 0.94 ^ (-min_armor)))
Если в результате подстановки значений верхняя граница меньше нижней, необходимо увеличивать значение max_life_bonus, пока неравенство не начнёт соблюдаться.

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

GetUnitArmorLib_ReturnValue
Специальная структура, объекты которой возвращает функция GetUnitArmor. Её объекты не нужно уничтожать.
Имеет следующие поля:
  • status - статус вычисления. Принимает значения с 0 по 4, все они занесены в константы структуры с префиксом STATUS.
    • 0 - вычисление выполнено успешно.
    • 1 - вычисление не было выполнено, потому что юнит не жив (то есть мёртв или не существует).
    • 2 - вычисление не было выполнено, потому что юнит неуязвим к магии и является эфириалом.
    • 3 - вычисление не было выполнено, потому что юнит не получил урон универсального типа.
    • 4 - вычисление не было выполнено, потому что юнит не получил урон нормального типа.
  • armor - вычисленное значение брони в случае успеха или 0 в противном случае.
Для удобства работы со статусом были созданы следующие поля-операторы:
  • rv.success - аналогично rv.status == 0.
  • rv.failure - аналогично rv.status != 0.
  • rv.failure_not_alive - аналогично rv.status == 1.
  • rv.failure_etherial_and_magic_immune - аналогично rv.status == 2.
  • rv.failure_no_damage - аналогично rv.status == 3 or rv.status == 4.
  • rv.failure_no_universal_damage - аналогично rv.status == 3.
  • rv.failure_no_normal_damage - аналогично rv.status == 4.
Также есть один метод:
  • rv.get_armor_or_value(real_value) - возвращает rv.amor, если rv.status == 0, и real_value в противном случае.
Важно: данная структура предназначена для локального использования. Если хранить её объекты в глобальных переменных или хранилищах, их значения могут измениться спустя какое-то время. Одновременно может существовать 8192 разных объектов этой структуры.
GetUnitArmor
local GetUnitArmorLib_ReturnValue rv = GetUnitArmor(some_unit)
Вычисляет броню для some_unit. Если это возможно, то rv.success будет true и вычисленное значение брони будет в rv.armor. Стоит отметить, что значения брони будут с некоторой погрешностью из-за вычислений.

Примеры

Трекер брони

Карта
Тестовая карта библиотеки. В карте минимальная броня равна -18, а максимальная равна 9900. Согласно неравенству, константа DamageAmount должна быть в диапазоне (7437.5, 180181.2). Но там указано 1000, отчего для некоторых значений и типов брони вычисление будет неверным.

Паладин

Карта
У паладина есть аура, которая обжигает нежить поблизости. Урон ауры зависит от количества брони или от статуса паладина.

Обновления

28.12.2025
  • Полностью переработана библиотека:
    • Теперь нужно настроить всего 3 значения.
    • Работает с эфириалами.
    • Функция GetUnitArmor возвращает специальную структуру со значением брони и статусом.
  • Обновлена тестовая карта.
  • Добавлена карта-пример.
25.12.2021
  • В код добавлены оригинальные формулы брони на случай, если указанные ссылки станут недоступны.
  • Залита последняя тестовая карта.
  • С эфириалами всё ещё не работает.
16.03.2021 - 4
  • Улучшена надёжность определения того, что урон наносится с целью вычислить броню.
  • Добавлена константа ValueWhenUnitInvulnerable.
16.03.2021 - 3
Убран даммик.
16.03.2021 - 2
  • Добавлена обработка случая, когда юнит неуязвим.
  • Обновлена карта-пример.
16.03.2021 - 1
EvalArmor возвращает true, если урон использовался для вычисления брони, false - если нет. Удобно использовать как условие для триггера, который отлавливает нанесение урона.
пример
function Trig_TakesDamage_Conditions takes nothing returns boolean
    return not EvalArmor()
endfunction

function Trig_TakesDamage_Actions takes nothing returns nothing
    // ваш код
endfunction

function InitTrig_TakesDamage takes nothing returns nothing
    set gg_trg_TakesDamage = CreateTrigger(  )
    call TriggerAddCondition( gg_trg_TakesDamage, Filter(function Trig_TakesDamage_Conditions) )
    call TriggerAddAction( gg_trg_TakesDamage, function Trig_TakesDamage_Actions )
endfunction
В данном примере действия триггера будут выполняться только в том случае, если урон наносился не с целью вычисления брони.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
28
Обновил либу, подробности в посте.

Обновил ещё разок, спасибо Bergi_Bear, что напомнил про неуязвимость.

Ещё раз обновил, теперь не требуется даммик.
28
Повысил надёжность и добавил ещё одну константу.
15
Присвоить константе AttackType такой тип атаки, у которого одинаковый бонус ко всем типам брони.
В жассе есть дыра с дополнительным типом атаки, она используется для определения типов брони и ее количества в разных системах. Обсуждение можно найти, например, тут.
Вкратце, базовые типы атаки заданы константами
ATTACK_TYPE_NORMAL = ConvertAttackType(0)
ATTACK_TYPE_MELEE = ConvertAttackType(1)
ATTACK_TYPE_PIERCE = ConvertAttackType(2)
ATTACK_TYPE_SIEGE = ConvertAttackType(3)
ATTACK_TYPE_MAGIC = ConvertAttackType(4)
ATTACK_TYPE_CHAOS = ConvertAttackType(5)
ATTACK_TYPE_HERO = ConvertAttackType(6)
Но влындив семерку промеж булочек мы получим тип атаки нерегулируемый игровыми константами
ATTACK_TYPE_HORNY = ConvertAttackType(7)
33
Так что, неуязвимый юнит вернёт 0 брони, допустим я сделал скил .
Броня героя: Увеличивают броню союзных юнитов на значение равно 50% брони героя. И допустим это паладин с божественным щитом, получается скил отработает в 0.
Тогда наверное в случае инвула, стоит возвращать последнее значение брони, которое удалось получить, это конечно тоже не точное, но всё таки не 0
28
Bergi_Bear, для этого нужно кешировать последнее значение брони для юнита. Причём нужно этот кеш убирать, когда юнит удалён или умер.
Так что пусть картодел сам решает, как ему с этим быть. Я специально добавил константу ValueWhenUnitInvulnerable. Можно поставить ей такое значение, которое не может получиться в игре. Это будет свидетельствовать о том, что юнит неуязвим.
28
GetLocalPlayer, и как показывает обсуждение, у такого типа бонус ко всем типам брони разный. Так что он не подходит.
15
Так что он не подходит.
Почему не подходит? Сначала ты делаешь вывод о типе брони, исходя из того как урон был модифицирован, а затем вычисляешь количество брони.
28
GetLocalPlayer, а, в этом плане. Возможно потом обновлю, спасибо.

В таком случае нужно наносить урон 2 раза, чтобы выяснить чистый урон у такого типа брони и урон с вычетом брони у такого типа брони.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.