initial commit
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
local ____lualib = require("lualib_bundle")
|
||||
local __TS__Class = ____lualib.__TS__Class
|
||||
local __TS__ClassExtends = ____lualib.__TS__ClassExtends
|
||||
local __TS__Decorate = ____lualib.__TS__Decorate
|
||||
local __TS__ObjectKeys = ____lualib.__TS__ObjectKeys
|
||||
local __TS__ObjectValues = ____lualib.__TS__ObjectValues
|
||||
local __TS__Delete = ____lualib.__TS__Delete
|
||||
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
|
||||
local ____incoming_damage_reduction_combine = require("utils.incoming_damage_reduction_combine")
|
||||
local removeStatsMultiplierIncomingDamageReductionSource = ____incoming_damage_reduction_combine.removeStatsMultiplierIncomingDamageReductionSource
|
||||
local setStatsMultiplierIncomingDamageReductionSource = ____incoming_damage_reduction_combine.setStatsMultiplierIncomingDamageReductionSource
|
||||
____exports.MODIFIER_STATS_MULTIPLIER = "modifier_stats_multiplier"
|
||||
--- Стабильные id источников для снятия в `modifier_arsenal_dynamic_stats.OnDestroy`.
|
||||
____exports.ARSENAL_STATS_MULTIPLIER_SOURCE_ID = {
|
||||
all_stats_pct = "arsenal_dyn_pct_all_stats",
|
||||
strength_pct = "arsenal_dyn_pct_str",
|
||||
agility_pct = "arsenal_dyn_pct_agi",
|
||||
intellect_pct = "arsenal_dyn_pct_int",
|
||||
outgoing_damage_pct = "arsenal_dyn_pct_outgoing",
|
||||
incoming_damage_reduction_pct = "arsenal_dyn_pct_incoming",
|
||||
attack_speed_pct = "arsenal_dyn_pct_as",
|
||||
move_speed_pct = "arsenal_dyn_pct_ms",
|
||||
base_damage_pct = "arsenal_dyn_pct_basedmg"
|
||||
}
|
||||
____exports.ability_stats_multiplier = __TS__Class()
|
||||
local ability_stats_multiplier = ____exports.ability_stats_multiplier
|
||||
ability_stats_multiplier.name = "ability_stats_multiplier"
|
||||
ability_stats_multiplier.____file_path = "scripts/vscripts/modifiers/modifier_stats_multiplier.lua"
|
||||
__TS__ClassExtends(ability_stats_multiplier, BaseAbility)
|
||||
function ability_stats_multiplier.prototype.GetIntrinsicModifierName(self)
|
||||
return "modifier_stats_multiplier"
|
||||
end
|
||||
function ability_stats_multiplier.prototype.IsHidden(self)
|
||||
return true
|
||||
end
|
||||
ability_stats_multiplier = __TS__Decorate(
|
||||
ability_stats_multiplier,
|
||||
ability_stats_multiplier,
|
||||
{registerAbility(nil)},
|
||||
{kind = "class", name = "ability_stats_multiplier"}
|
||||
)
|
||||
____exports.ability_stats_multiplier = ability_stats_multiplier
|
||||
local globalModifierFunctionSourceSeq = 1
|
||||
function ____exports.createModifierFunctionSourceId(self, prefix)
|
||||
local safePrefix = prefix and #prefix > 0 and prefix or "source"
|
||||
local id = (safePrefix .. "_") .. tostring(globalModifierFunctionSourceSeq)
|
||||
globalModifierFunctionSourceSeq = globalModifierFunctionSourceSeq + 1
|
||||
return id
|
||||
end
|
||||
local function sourceKind(self, s)
|
||||
return s.kind or "attributes"
|
||||
end
|
||||
local function getStorage(self, hero)
|
||||
local holder = hero
|
||||
if not holder.__statsMultiplierStorage then
|
||||
holder.__statsMultiplierStorage = {}
|
||||
end
|
||||
return holder.__statsMultiplierStorage
|
||||
end
|
||||
local function hasSources(self, hero)
|
||||
return #__TS__ObjectKeys(getStorage(nil, hero)) > 0
|
||||
end
|
||||
--- Только карточные % к атрибутам — для видимости баффа и тултипа «%».
|
||||
local function hasAttributeSources(self, hero)
|
||||
local storage = getStorage(nil, hero)
|
||||
for ____, source in ipairs(__TS__ObjectValues(storage)) do
|
||||
if sourceKind(nil, source) == "attributes" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
--- Сбросить кэш сумм (арсенал/колоды меняются без смены id источника).
|
||||
function ____exports.invalidateStatsMultiplierSumCache(self, hero)
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return
|
||||
end
|
||||
local c = hero.__statsMultiplierSumCache
|
||||
if c then
|
||||
c.dirty = true
|
||||
end
|
||||
end
|
||||
local function rebuildSumCache(self, hero, cache)
|
||||
local storage = getStorage(nil, hero)
|
||||
local byKind = {}
|
||||
for ____, source in ipairs(__TS__ObjectValues(storage)) do
|
||||
local k = sourceKind(nil, source)
|
||||
byKind[k] = (byKind[k] or 0) + source:resolver()
|
||||
end
|
||||
cache.byKind = byKind
|
||||
cache.dirty = false
|
||||
end
|
||||
local function sumForKind(self, hero, kind)
|
||||
local holder = hero
|
||||
local cache = holder.__statsMultiplierSumCache
|
||||
if not cache then
|
||||
cache = {dirty = true, byKind = {}}
|
||||
holder.__statsMultiplierSumCache = cache
|
||||
end
|
||||
if cache.dirty then
|
||||
rebuildSumCache(nil, hero, cache)
|
||||
end
|
||||
return cache.byKind[kind] or 0
|
||||
end
|
||||
local function ensureModifier(self, hero)
|
||||
if not hero:FindModifierByName(____exports.MODIFIER_STATS_MULTIPLIER) then
|
||||
local sourceAbility = hero:FindAbilityByName("ability_stats_multiplier") or hero:FindAbilityByName("ability_stacking_crit")
|
||||
hero:AddNewModifier(hero, sourceAbility, ____exports.MODIFIER_STATS_MULTIPLIER, {})
|
||||
end
|
||||
end
|
||||
local function removeModifierIfUnused(self, hero)
|
||||
if hasSources(nil, hero) then
|
||||
return
|
||||
end
|
||||
local mod = hero:FindModifierByName(____exports.MODIFIER_STATS_MULTIPLIER)
|
||||
if mod then
|
||||
mod:Destroy()
|
||||
end
|
||||
____exports.invalidateStatsMultiplierSumCache(nil, hero)
|
||||
end
|
||||
--- Регистрирует вклад в `modifier_stats_multiplier`.
|
||||
-- - `kind === "attributes"` (по умолчанию): сумма % умножается на **базовые** Str/Agi/Int и даёт бонус к соответствующему атрибуту (карты).
|
||||
-- - `all_stats_pct`: тот же % к **каждой** базовой характеристике Str/Agi/Int (арсенал).
|
||||
-- - `strength_pct` / `agility_pct` / `intellect_pct`: % только к **базовому** Str/Agi/Int (арсенал).
|
||||
-- - Остальные `kind`: сумма идёт в соответствующий `ModifierFunction` (исходящий/входящий урон, AS%/MS%, урон от базы атаки) — арсенал;
|
||||
-- для `incoming_damage_reduction_pct` сумма **не** добавляется линейно в движок, а сжимается формулой с убыванием (см. `incoming_damage_reduction_combine`).
|
||||
function ____exports.setStatsMultiplierSource(self, hero, sourceId, resolver, kind)
|
||||
if kind == nil then
|
||||
kind = "attributes"
|
||||
end
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return
|
||||
end
|
||||
getStorage(nil, hero)[sourceId] = {resolver = resolver, kind = kind}
|
||||
if kind == "incoming_damage_reduction_pct" then
|
||||
setStatsMultiplierIncomingDamageReductionSource(nil, hero, sourceId, resolver)
|
||||
end
|
||||
____exports.invalidateStatsMultiplierSumCache(nil, hero)
|
||||
ensureModifier(nil, hero)
|
||||
end
|
||||
function ____exports.removeStatsMultiplierSource(self, hero, sourceId)
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return
|
||||
end
|
||||
local storage = getStorage(nil, hero)
|
||||
local removed = storage[sourceId]
|
||||
if removed and sourceKind(nil, removed) == "incoming_damage_reduction_pct" then
|
||||
removeStatsMultiplierIncomingDamageReductionSource(nil, hero, sourceId)
|
||||
end
|
||||
__TS__Delete(storage, sourceId)
|
||||
____exports.invalidateStatsMultiplierSumCache(nil, hero)
|
||||
removeModifierIfUnused(nil, hero)
|
||||
end
|
||||
____exports.modifier_stats_multiplier = __TS__Class()
|
||||
local modifier_stats_multiplier = ____exports.modifier_stats_multiplier
|
||||
modifier_stats_multiplier.name = "modifier_stats_multiplier"
|
||||
modifier_stats_multiplier.____file_path = "scripts/vscripts/modifiers/modifier_stats_multiplier.lua"
|
||||
__TS__ClassExtends(modifier_stats_multiplier, BaseModifier)
|
||||
function modifier_stats_multiplier.prototype.____constructor(self, ...)
|
||||
BaseModifier.prototype.____constructor(self, ...)
|
||||
self.lock = false
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.IsHidden(self)
|
||||
local parent = self:GetParent()
|
||||
if not parent or not IsValidEntity(parent) then
|
||||
return true
|
||||
end
|
||||
return not hasAttributeSources(nil, parent)
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.RemoveOnDeath(self)
|
||||
return false
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.IsPurgable(self)
|
||||
return false
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.GetTexture(self)
|
||||
return "nevermore_dark_lord"
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.DeclareFunctions(self)
|
||||
return {
|
||||
MODIFIER_PROPERTY_STATS_STRENGTH_BONUS,
|
||||
MODIFIER_PROPERTY_STATS_AGILITY_BONUS,
|
||||
MODIFIER_PROPERTY_STATS_INTELLECT_BONUS,
|
||||
MODIFIER_PROPERTY_TOOLTIP,
|
||||
MODIFIER_PROPERTY_DAMAGEOUTGOING_PERCENTAGE,
|
||||
MODIFIER_PROPERTY_ATTACKSPEED_PERCENTAGE,
|
||||
MODIFIER_PROPERTY_MOVESPEED_BONUS_PERCENTAGE,
|
||||
MODIFIER_PROPERTY_BASEDAMAGEOUTGOING_PERCENTAGE
|
||||
}
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.sumResolverPercentAttributes(self)
|
||||
local hero = self:GetParent()
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return 0
|
||||
end
|
||||
return sumForKind(nil, hero, "attributes")
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.OnTooltip(self)
|
||||
if not IsServer() then
|
||||
return 0
|
||||
end
|
||||
return self:sumResolverPercentAttributes()
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.GetModifierBonusStats_Strength(self)
|
||||
if self.lock then
|
||||
return 0
|
||||
end
|
||||
local hero = self:GetParent()
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return 0
|
||||
end
|
||||
self.lock = true
|
||||
local base = hero:GetStrength() or 0
|
||||
local shared = sumForKind(nil, hero, "all_stats_pct")
|
||||
local pct = self:sumResolverPercentAttributes() + shared + sumForKind(nil, hero, "strength_pct")
|
||||
local v = base * (pct / 100)
|
||||
self.lock = false
|
||||
return v
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.GetModifierBonusStats_Agility(self)
|
||||
if self.lock then
|
||||
return 0
|
||||
end
|
||||
local hero = self:GetParent()
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return 0
|
||||
end
|
||||
self.lock = true
|
||||
local base = hero:GetAgility() or 0
|
||||
local shared = sumForKind(nil, hero, "all_stats_pct")
|
||||
local pct = self:sumResolverPercentAttributes() + shared + sumForKind(nil, hero, "agility_pct")
|
||||
local v = base * (pct / 100)
|
||||
self.lock = false
|
||||
return v
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.GetModifierBonusStats_Intellect(self)
|
||||
if self.lock then
|
||||
return 0
|
||||
end
|
||||
local hero = self:GetParent()
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return 0
|
||||
end
|
||||
self.lock = true
|
||||
local base = hero:GetIntellect(true) or 0
|
||||
local shared = sumForKind(nil, hero, "all_stats_pct")
|
||||
local pct = self:sumResolverPercentAttributes() + shared + sumForKind(nil, hero, "intellect_pct")
|
||||
local v = base * (pct / 100)
|
||||
self.lock = false
|
||||
return v
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.GetModifierDamageOutgoing_Percentage(self)
|
||||
local hero = self:GetParent()
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return 0
|
||||
end
|
||||
return sumForKind(nil, hero, "outgoing_damage_pct")
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.GetModifierAttackSpeedPercentage(self)
|
||||
local hero = self:GetParent()
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return 0
|
||||
end
|
||||
return sumForKind(nil, hero, "attack_speed_pct")
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.GetModifierMoveSpeedBonus_Percentage(self)
|
||||
local hero = self:GetParent()
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return 0
|
||||
end
|
||||
return sumForKind(nil, hero, "move_speed_pct")
|
||||
end
|
||||
function modifier_stats_multiplier.prototype.GetModifierBaseDamageOutgoing_Percentage(self)
|
||||
local hero = self:GetParent()
|
||||
if not hero or not IsValidEntity(hero) then
|
||||
return 0
|
||||
end
|
||||
return sumForKind(nil, hero, "base_damage_pct")
|
||||
end
|
||||
modifier_stats_multiplier = __TS__Decorate(
|
||||
modifier_stats_multiplier,
|
||||
modifier_stats_multiplier,
|
||||
{registerModifier(nil)},
|
||||
{kind = "class", name = "modifier_stats_multiplier"}
|
||||
)
|
||||
____exports.modifier_stats_multiplier = modifier_stats_multiplier
|
||||
return ____exports
|
||||
Reference in New Issue
Block a user