Добавлен PT153,
опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
vJass
Тип:
Наработка
Версия Warcraft:
1.26+
Библиотека, добавляющая возможность вычислять текущую броню юнита, включая все бонусы.
код
library ArmorLib initializer init requires NegateDamageLib, MathLib
globals
private key ParentKey
private real LogBase
private constant attacktype AttackType = ATTACK_TYPE_CHAOS
private constant real AttackType_Mutliplier = 1.
private constant real ArmorDamageReductionMultiplier = 0.06
private constant real EtherealHealBonus = 1.66
private constant real Damage = 1000.
private constant real ValueWhenUnitInvulnerable = 0.
endglobals
function GetUnitArmor takes unit u returns real
local integer id = GetHandleId(u)
local real armor
call SaveBoolean(Hash, ParentKey, id, false)
call SaveInteger(Hash, ParentKey, id, 1)
call UnitDamageTarget(u, u, Damage, false, false, AttackType, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
if not HaveSavedReal(Hash, ParentKey, id) then
// unit is ethereal
call SaveBoolean(Hash, ParentKey, id, true)
call UnitDamageTarget(u, u, Damage, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
set armor = LoadReal(Hash, ParentKey, id)
call RemoveSavedBoolean(Hash, ParentKey, id)
call RemoveSavedInteger(Hash, ParentKey, id) // redundant, but necessary if no trigger for damage is defined
call RemoveSavedReal(Hash, ParentKey, id)
return armor
endfunction
function EvalArmor takes nothing returns boolean
local integer id = GetHandleId(GetTriggerUnit())
local real reduction
local real armor
if HaveSavedInteger(Hash, ParentKey, id) then
call RemoveSavedInteger(Hash, ParentKey, id)
if GetEventDamage() > 0. then
call NegateDamage(GetTriggerUnit(), GetEventDamage())
// total_damage = damage * (1 - reduction) * armor_type_multiplier
// reduction = 1 - total_damage / damage / armor_type_multiplier
if LoadBoolean(Hash, ParentKey, id) then
// unit is ethereal
set reduction = 1. - GetEventDamage() / Damage / EtherealHealBonus
else
set reduction = 1. - GetEventDamage() / Damage / AttackType_Mutliplier
endif
// For armor formulas, please, refer to these articles
// http://classic.battle.net/war3/basics/armorandweapontypes.shtml
// https://warcraft3.info/articles/208/overview-of-armor-and-damage-reduction
// armor > 0 -- Damage Reduction = (armor * constant) / (1 + constant * armor)
// armor < 0 -- Damage Increment = 2 - (1 - constant) ^ (-armor)
if reduction < 0. then
// -reduction = 1 - (1 - multiplier) ^ (-armor)
// reduction = (1 - multiplier) ^ (-armor) - 1
// armor = - ln(reduction + 1) / ln(1 - multiplier)
set armor = - Ln(reduction + 1.) / LogBase
else
// reduction = multiplier * armor / (1 + multiplier * armor)
// armor = reduction / multiplier / (1 - reduction)
set armor = reduction / ArmorDamageReductionMultiplier / (1. - reduction)
endif
else
set armor = ValueWhenUnitInvulnerable
endif
call SaveReal(Hash, ParentKey, id, armor)
return true
endif
return false
endfunction
private function init takes nothing returns nothing
set LogBase = Ln(1. - ArmorDamageReductionMultiplier)
endfunction
endlibrary
Требования
- Math library
- Negate Damage library
- Наличие триггера, который срабатывает на получение урона юнитом, для которого необходимо узнать количество брони. Пример такого триггера можно посмотреть тут и в карте-примере.
Настройка
- Присвоить константе AttackType такой тип атаки, у которого одинаковый бонус ко всем типам брони. По умолчанию это Chaos. Не может быть типом атаки Magic.
- Присвоить константе AttackType_Mutliplier значение мультипликатора бонуса выбранного типа атаки. По умолчанию 1, как в стандарте.
- Присвоить константе ArmorDamageReductionMultiplier значение игровой константы DefenseArmor (Armor Damage Reduction Multiplier). По умолчанию 0.06, как в стандарте.
- Присвоить константе EtherealHealBonus значение игровой константы EtherealHealBonus (Ethereal Heal Bonus). По умолчанию 1.66, как в стандарте.
- Присвоить константе Damage значение урона, которое будет наносится для вычисления брони. Рекомендуется оставить неизменным. Значение должно быть больше нуля.
- Присвоить константе ValueWhenUnitInvulnerable значение брони, которое хотите получать, когда юнит неуязвим. По умолчанию 0.
- В триггере, который отслеживает получение урона, нужно добавить вызов функции EvalArmor.
пример
Если у триггера есть условие, то тогда EvalArmor нужно вызывать следующим образом:
function Trig_TakesDamage_Conditions takes nothing returns boolean
return not EvalArmor() and (/* тут другие условия, которые должны быть соблюдены */)
endfunction
Если нет, то тогда можно добавить в сами действия:
function Trig_TakesDamage_Actions takes nothing returns nothing
if EvalArmor() then
return
endif
// другие действия
endfunction
Использование
Чтобы узнать текущую броню юнита u, вызовите GetUnitArmor(u).
Ограничения
- Так как используются вычисления, то значения брони будут с некоторой погрешностью.
- Если юнит неуязвим, функция вернёт значение константы ValueWhenUnitInvulnerable.
Пример
В карте изменены мультипликаторы урона для типа атаки Chaos - все увеличены вдвое. Это было сделано с целью демонстрации.
Обновления
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
В данном примере действия триггера будут выполняться только в том случае, если урон наносился не с целью вычисления брони.
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Вкратце, базовые типы атаки заданы константами
Броня героя: Увеличивают броню союзных юнитов на значение равно 50% брони героя. И допустим это паладин с божественным щитом, получается скил отработает в 0.
Тогда наверное в случае инвула, стоит возвращать последнее значение брони, которое удалось получить, это конечно тоже не точное, но всё таки не 0
Отредактирован PT153
Так что пусть картодел сам решает, как ему с этим быть. Я специально добавил константу ValueWhenUnitInvulnerable. Можно поставить ей такое значение, которое не может получиться в игре. Это будет свидетельствовать о том, что юнит неуязвим.
Отредактирован PT153