163 lines
7.6 KiB
Lua
163 lines
7.6 KiB
Lua
local ____lualib = require("lualib_bundle")
|
||
local __TS__NumberIsFinite = ____lualib.__TS__NumberIsFinite
|
||
local __TS__ObjectKeys = ____lualib.__TS__ObjectKeys
|
||
local __TS__ObjectValues = ____lualib.__TS__ObjectValues
|
||
local __TS__Delete = ____lualib.__TS__Delete
|
||
local __TS__Class = ____lualib.__TS__Class
|
||
local __TS__ClassExtends = ____lualib.__TS__ClassExtends
|
||
local __TS__Decorate = ____lualib.__TS__Decorate
|
||
local ____exports = {}
|
||
local ____dota_ts_adapter = require("lib.dota_ts_adapter")
|
||
local BaseAbility = ____dota_ts_adapter.BaseAbility
|
||
local BaseModifier = ____dota_ts_adapter.BaseModifier
|
||
local registerAbility = ____dota_ts_adapter.registerAbility
|
||
local registerModifier = ____dota_ts_adapter.registerModifier
|
||
--- Верхний предел после убывания (синхрон с `src/panorama/arsenal.ts`).
|
||
____exports.MAX_EFFECTIVE_INCOMING_REDUCTION_FROM_LINEAR_SUM_PCT = 92
|
||
--- «Бумажная» сумма % снижения входящего → эффективный % в бою (убывающая отдача).
|
||
--
|
||
-- @param linearSumPositivePct сумма вкладов из KV/арсенала (+20+20+…)
|
||
function ____exports.resolveIncomingDamageReductionPctFromLinearSum(self, linearSumPositivePct)
|
||
if not __TS__NumberIsFinite(linearSumPositivePct) or linearSumPositivePct <= 0 then
|
||
return 0
|
||
end
|
||
local s = linearSumPositivePct
|
||
local hyperbolic = 100 * s / (100 + s)
|
||
return math.min(____exports.MAX_EFFECTIVE_INCOMING_REDUCTION_FROM_LINEAR_SUM_PCT, hyperbolic)
|
||
end
|
||
--- Значение для MODIFIER_PROPERTY_INCOMING_DAMAGE_PERCENTAGE (отрицательное = меньше урона).
|
||
function ____exports.incomingDamageReductionModifierValue(self, linearSumPositivePct)
|
||
local effective = ____exports.resolveIncomingDamageReductionPctFromLinearSum(nil, linearSumPositivePct)
|
||
return effective > 0 and -effective or 0
|
||
end
|
||
____exports.MODIFIER_INCOMING_DAMAGE_REDUCTION = "modifier_incoming_damage_reduction"
|
||
local STATS_MULTIPLIER_INCOMING_PREFIX = "stats_multiplier:"
|
||
local function getStorage(self, unit)
|
||
local holder = unit
|
||
if not holder.__incomingDamageReductionStorage then
|
||
holder.__incomingDamageReductionStorage = {sources = {}, eventSources = {}}
|
||
end
|
||
return holder.__incomingDamageReductionStorage
|
||
end
|
||
local function hasAnySources(self, unit)
|
||
local storage = getStorage(nil, unit)
|
||
return #__TS__ObjectKeys(storage.sources) > 0 or #__TS__ObjectKeys(storage.eventSources) > 0
|
||
end
|
||
local function resolveSourceAbility(self, unit)
|
||
return unit:FindAbilityByName("ability_incoming_damage_reduction") or unit:FindAbilityByName("ability_stats_multiplier") or unit:FindAbilityByName("ability_stacking_crit") or nil
|
||
end
|
||
local function ensureCombineModifier(self, unit)
|
||
if unit:FindModifierByName(____exports.MODIFIER_INCOMING_DAMAGE_REDUCTION) then
|
||
return
|
||
end
|
||
local sourceAbility = resolveSourceAbility(nil, unit)
|
||
unit:AddNewModifier(unit, sourceAbility, ____exports.MODIFIER_INCOMING_DAMAGE_REDUCTION, {})
|
||
end
|
||
local function removeCombineModifierIfUnused(self, unit)
|
||
if hasAnySources(nil, unit) then
|
||
return
|
||
end
|
||
local mod = unit:FindModifierByName(____exports.MODIFIER_INCOMING_DAMAGE_REDUCTION)
|
||
if mod then
|
||
mod:Destroy()
|
||
end
|
||
end
|
||
--- Сумма «бумажных» % снижения (до формулы убывания).
|
||
function ____exports.computeIncomingDamageReductionLinearSum(self, unit, event)
|
||
local storage = getStorage(nil, unit)
|
||
local sum = 0
|
||
for ____, entry in ipairs(__TS__ObjectValues(storage.sources)) do
|
||
local value = entry:resolver()
|
||
if __TS__NumberIsFinite(value) and value > 0 then
|
||
sum = sum + value
|
||
end
|
||
end
|
||
if event then
|
||
for ____, entry in ipairs(__TS__ObjectValues(storage.eventSources)) do
|
||
local value = entry:resolver(event)
|
||
if __TS__NumberIsFinite(value) and value > 0 then
|
||
sum = sum + value
|
||
end
|
||
end
|
||
end
|
||
return sum
|
||
end
|
||
--- Статический/динамический источник: resolver возвращает положительный % снижения.
|
||
function ____exports.setIncomingDamageReductionSource(self, unit, sourceId, resolver)
|
||
if not unit or not IsValidEntity(unit) then
|
||
return
|
||
end
|
||
getStorage(nil, unit).sources[sourceId] = {resolver = resolver}
|
||
ensureCombineModifier(nil, unit)
|
||
end
|
||
--- Источник, зависящий от удара (угол, золото, мана и т.д.).
|
||
function ____exports.setIncomingDamageReductionEventSource(self, unit, sourceId, resolver)
|
||
if not unit or not IsValidEntity(unit) then
|
||
return
|
||
end
|
||
getStorage(nil, unit).eventSources[sourceId] = {resolver = resolver}
|
||
ensureCombineModifier(nil, unit)
|
||
end
|
||
function ____exports.removeIncomingDamageReductionSource(self, unit, sourceId)
|
||
if not unit or not IsValidEntity(unit) then
|
||
return
|
||
end
|
||
local storage = getStorage(nil, unit)
|
||
__TS__Delete(storage.sources, sourceId)
|
||
__TS__Delete(storage.eventSources, sourceId)
|
||
removeCombineModifierIfUnused(nil, unit)
|
||
end
|
||
function ____exports.setStatsMultiplierIncomingDamageReductionSource(self, hero, sourceId, resolver)
|
||
____exports.setIncomingDamageReductionSource(nil, hero, STATS_MULTIPLIER_INCOMING_PREFIX .. sourceId, resolver)
|
||
end
|
||
function ____exports.removeStatsMultiplierIncomingDamageReductionSource(self, hero, sourceId)
|
||
____exports.removeIncomingDamageReductionSource(nil, hero, STATS_MULTIPLIER_INCOMING_PREFIX .. sourceId)
|
||
end
|
||
local ability_incoming_damage_reduction = __TS__Class()
|
||
ability_incoming_damage_reduction.name = "ability_incoming_damage_reduction"
|
||
ability_incoming_damage_reduction.____file_path = "scripts/vscripts/utils/incoming_damage_reduction_combine.lua"
|
||
__TS__ClassExtends(ability_incoming_damage_reduction, BaseAbility)
|
||
function ability_incoming_damage_reduction.prototype.GetIntrinsicModifierName(self)
|
||
return ____exports.MODIFIER_INCOMING_DAMAGE_REDUCTION
|
||
end
|
||
function ability_incoming_damage_reduction.prototype.IsHidden(self)
|
||
return true
|
||
end
|
||
ability_incoming_damage_reduction = __TS__Decorate(
|
||
ability_incoming_damage_reduction,
|
||
ability_incoming_damage_reduction,
|
||
{registerAbility(nil)},
|
||
{kind = "class", name = "ability_incoming_damage_reduction"}
|
||
)
|
||
local modifier_incoming_damage_reduction = __TS__Class()
|
||
modifier_incoming_damage_reduction.name = "modifier_incoming_damage_reduction"
|
||
modifier_incoming_damage_reduction.____file_path = "scripts/vscripts/utils/incoming_damage_reduction_combine.lua"
|
||
__TS__ClassExtends(modifier_incoming_damage_reduction, BaseModifier)
|
||
function modifier_incoming_damage_reduction.prototype.IsHidden(self)
|
||
return true
|
||
end
|
||
function modifier_incoming_damage_reduction.prototype.IsPurgable(self)
|
||
return false
|
||
end
|
||
function modifier_incoming_damage_reduction.prototype.RemoveOnDeath(self)
|
||
return false
|
||
end
|
||
function modifier_incoming_damage_reduction.prototype.DeclareFunctions(self)
|
||
return {MODIFIER_PROPERTY_INCOMING_DAMAGE_PERCENTAGE}
|
||
end
|
||
function modifier_incoming_damage_reduction.prototype.GetModifierIncomingDamage_Percentage(self, event)
|
||
local unit = self:GetParent()
|
||
if not unit or not IsValidEntity(unit) then
|
||
return 0
|
||
end
|
||
local linearSum = ____exports.computeIncomingDamageReductionLinearSum(nil, unit, event)
|
||
return ____exports.incomingDamageReductionModifierValue(nil, linearSum)
|
||
end
|
||
modifier_incoming_damage_reduction = __TS__Decorate(
|
||
modifier_incoming_damage_reduction,
|
||
modifier_incoming_damage_reduction,
|
||
{registerModifier(nil)},
|
||
{kind = "class", name = "modifier_incoming_damage_reduction"}
|
||
)
|
||
return ____exports
|