local ____lualib = require("lualib_bundle") local __TS__ObjectValues = ____lualib.__TS__ObjectValues local __TS__ObjectAssign = ____lualib.__TS__ObjectAssign 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 BaseModifier = ____dota_ts_adapter.BaseModifier local registerModifier = ____dota_ts_adapter.registerModifier local ____ArsenalStatRuntime = require("arsenal.ArsenalStatRuntime") local getArsenalTotals = ____ArsenalStatRuntime.getArsenalTotals local ____modifier_stats_multiplier = require("modifiers.modifier_stats_multiplier") local ARSENAL_STATS_MULTIPLIER_SOURCE_ID = ____modifier_stats_multiplier.ARSENAL_STATS_MULTIPLIER_SOURCE_ID local invalidateStatsMultiplierSumCache = ____modifier_stats_multiplier.invalidateStatsMultiplierSumCache local removeStatsMultiplierSource = ____modifier_stats_multiplier.removeStatsMultiplierSource local setStatsMultiplierSource = ____modifier_stats_multiplier.setStatsMultiplierSource local ____incoming_damage_reduction_combine = require("utils.incoming_damage_reduction_combine") local removeIncomingDamageReductionSource = ____incoming_damage_reduction_combine.removeIncomingDamageReductionSource local setIncomingDamageReductionSource = ____incoming_damage_reduction_combine.setIncomingDamageReductionSource local ____luck = require("utils.luck") local addLuck = ____luck.addLuck local reduceLuck = ____luck.reduceLuck local ____crit_mult = require("utils.crit_mult") local addCritMult = ____crit_mult.addCritMult local reduceCritMult = ____crit_mult.reduceCritMult local ZERO_TOTALS = { battle_level = 0, bonus_damage = 0, attack_speed = 0, bonus_armor = 0, max_health = 0, max_mana = 0, health_regen = 0, mana_regen = 0, move_speed = 0, magic_resist = 0, spell_amp = 0, all_stats = 0, all_stats_pct = 0, bonus_strength = 0, bonus_agility = 0, bonus_intellect = 0, strength_pct = 0, agility_pct = 0, intellect_pct = 0, luck = 0, outgoing_damage_pct = 0, incoming_damage_reduction_pct = 0, attack_speed_pct = 0, move_speed_pct = 0, base_damage_pct = 0, crit_mult = 0 } --- % атрибутов — через stats multiplier (база × %). Боевые % — прямо в DeclareFunctions ниже. local ARSENAL_ATTRIBUTE_PCT_KINDS = {"all_stats_pct", "strength_pct", "agility_pct", "intellect_pct"} local ALL_ARSENAL_MULTIPLIER_SOURCE_IDS = __TS__ObjectValues(ARSENAL_STATS_MULTIPLIER_SOURCE_ID) local ARSENAL_INCOMING_REDUCTION_SOURCE_ID = "arsenal_dynamic_stats_incoming" --- Раньше вешались на stats_multiplier — снимаем, чтобы не дублировать с прямым DeclareFunctions. local ARSENAL_LEGACY_COMBAT_PCT_KINDS = { "outgoing_damage_pct", "incoming_damage_reduction_pct", "attack_speed_pct", "move_speed_pct", "base_damage_pct" } local function coerceTotals(self, next) if not next then return __TS__ObjectAssign({}, ZERO_TOTALS) end return { battle_level = next.battle_level or 0, bonus_damage = next.bonus_damage or 0, attack_speed = next.attack_speed or 0, bonus_armor = next.bonus_armor or 0, max_health = next.max_health or 0, max_mana = next.max_mana or 0, health_regen = next.health_regen or 0, mana_regen = next.mana_regen or 0, move_speed = next.move_speed or 0, magic_resist = next.magic_resist or 0, spell_amp = next.spell_amp or 0, all_stats = next.all_stats or 0, all_stats_pct = next.all_stats_pct or 0, bonus_strength = next.bonus_strength or 0, bonus_agility = next.bonus_agility or 0, bonus_intellect = next.bonus_intellect or 0, strength_pct = next.strength_pct or 0, agility_pct = next.agility_pct or 0, intellect_pct = next.intellect_pct or 0, luck = next.luck or 0, outgoing_damage_pct = next.outgoing_damage_pct or 0, incoming_damage_reduction_pct = next.incoming_damage_reduction_pct or 0, attack_speed_pct = next.attack_speed_pct or 0, move_speed_pct = next.move_speed_pct or 0, base_damage_pct = next.base_damage_pct or 0, crit_mult = next.crit_mult or 0 } end ____exports.modifier_arsenal_dynamic_stats = __TS__Class() local modifier_arsenal_dynamic_stats = ____exports.modifier_arsenal_dynamic_stats modifier_arsenal_dynamic_stats.name = "modifier_arsenal_dynamic_stats" modifier_arsenal_dynamic_stats.____file_path = "scripts/vscripts/arsenal/items/dynamic_stats.lua" __TS__ClassExtends(modifier_arsenal_dynamic_stats, BaseModifier) function modifier_arsenal_dynamic_stats.prototype.____constructor(self, ...) BaseModifier.prototype.____constructor(self, ...) self.totals = __TS__ObjectAssign({}, ZERO_TOTALS) self.appliedLuckFromArsenal = 0 self.appliedCritMultFromArsenal = 0 end function modifier_arsenal_dynamic_stats.prototype.OnCreated(self) if not IsServer() then return end self:SetHasCustomTransmitterData(true) self:refreshTotalsFromServer() self:applyBattleLevelFromTotals() self:syncLuckFromTotals() self:syncCritMultFromTotals() self:wireArsenalAttributePctSources() self:wireArsenalIncomingReductionSource() end function modifier_arsenal_dynamic_stats.prototype.OnRefresh(self) if not IsServer() then return end self:refreshTotalsFromServer() self:applyBattleLevelFromTotals() self:syncLuckFromTotals() self:syncCritMultFromTotals() self:wireArsenalAttributePctSources() self:wireArsenalIncomingReductionSource() end function modifier_arsenal_dynamic_stats.prototype.OnDestroy(self) if not IsServer() then return end self:clearLuckFromTotals() self:clearCritMultFromTotals() self:unwireAllArsenalMultiplierSources() self:unwireArsenalIncomingReductionSource() end function modifier_arsenal_dynamic_stats.prototype.wireArsenalIncomingReductionSource(self) local hero = self:GetParent() if not hero or not IsValidEntity(hero) or not hero:IsRealHero() then return end setIncomingDamageReductionSource( nil, hero, ARSENAL_INCOMING_REDUCTION_SOURCE_ID, function() if not hero or not IsValidEntity(hero) then return 0 end local totals = coerceTotals( nil, getArsenalTotals(nil, hero) ) return math.max(0, totals.incoming_damage_reduction_pct or 0) end ) end function modifier_arsenal_dynamic_stats.prototype.unwireArsenalIncomingReductionSource(self) local hero = self:GetParent() if not hero or not IsValidEntity(hero) then return end removeIncomingDamageReductionSource(nil, hero, ARSENAL_INCOMING_REDUCTION_SOURCE_ID) end function modifier_arsenal_dynamic_stats.prototype.unwireLegacyArsenalCombatPctSources(self, hero) for ____, k in ipairs(ARSENAL_LEGACY_COMBAT_PCT_KINDS) do removeStatsMultiplierSource(nil, hero, ARSENAL_STATS_MULTIPLIER_SOURCE_ID[k]) end end function modifier_arsenal_dynamic_stats.prototype.wireArsenalAttributePctSources(self) local hero = self:GetParent() if not hero or not IsValidEntity(hero) or not hero:IsRealHero() then return end self:unwireLegacyArsenalCombatPctSources(hero) for ____, k in ipairs(ARSENAL_ATTRIBUTE_PCT_KINDS) do local sourceId = ARSENAL_STATS_MULTIPLIER_SOURCE_ID[k] setStatsMultiplierSource( nil, hero, sourceId, function() if not hero or not IsValidEntity(hero) then return 0 end local t = coerceTotals( nil, getArsenalTotals(nil, hero) ) if k == "strength_pct" then return t.strength_pct end if k == "agility_pct" then return t.agility_pct end if k == "intellect_pct" then return t.intellect_pct end if k == "all_stats_pct" then return t.all_stats_pct end return 0 end, k ) end end function modifier_arsenal_dynamic_stats.prototype.unwireAllArsenalMultiplierSources(self) local hero = self:GetParent() if not hero or not IsValidEntity(hero) then return end for ____, sourceId in ipairs(ALL_ARSENAL_MULTIPLIER_SOURCE_IDS) do removeStatsMultiplierSource(nil, hero, sourceId) end end function modifier_arsenal_dynamic_stats.prototype.AddCustomTransmitterData(self) return self.totals end function modifier_arsenal_dynamic_stats.prototype.HandleCustomTransmitterData(self, data) self.totals = coerceTotals(nil, data) end function modifier_arsenal_dynamic_stats.prototype.refreshTotalsFromServer(self) local parent = self:GetParent() local hero = parent local next = getArsenalTotals(nil, hero) self.totals = coerceTotals(nil, next) self:SendBuffRefreshToClients() if hero and IsValidEntity(hero) and hero:IsRealHero() then invalidateStatsMultiplierSumCache(nil, hero) end end function modifier_arsenal_dynamic_stats.prototype.syncLuckFromTotals(self) local hero = self:GetParent() if not hero or not IsValidEntity(hero) or not hero:IsRealHero() then return end local targetLuck = self:getTotals().luck or 0 local delta = targetLuck - self.appliedLuckFromArsenal if math.abs(delta) <= 0.0001 then return end if delta > 0 then addLuck(nil, hero, delta) else reduceLuck(nil, hero, -delta) end self.appliedLuckFromArsenal = targetLuck end function modifier_arsenal_dynamic_stats.prototype.clearLuckFromTotals(self) local hero = self:GetParent() if not hero or not IsValidEntity(hero) or not hero:IsRealHero() then return end if math.abs(self.appliedLuckFromArsenal) <= 0.0001 then return end if self.appliedLuckFromArsenal > 0 then reduceLuck(nil, hero, self.appliedLuckFromArsenal) else addLuck(nil, hero, -self.appliedLuckFromArsenal) end self.appliedLuckFromArsenal = 0 end function modifier_arsenal_dynamic_stats.prototype.syncCritMultFromTotals(self) local hero = self:GetParent() if not hero or not IsValidEntity(hero) or not hero:IsRealHero() then return end local targetCrit = self:getTotals().crit_mult or 0 local delta = targetCrit - self.appliedCritMultFromArsenal if math.abs(delta) <= 0.0001 then return end if delta > 0 then addCritMult(nil, hero, delta) else reduceCritMult(nil, hero, -delta) end self.appliedCritMultFromArsenal = targetCrit end function modifier_arsenal_dynamic_stats.prototype.clearCritMultFromTotals(self) local hero = self:GetParent() if not hero or not IsValidEntity(hero) or not hero:IsRealHero() then return end if math.abs(self.appliedCritMultFromArsenal) <= 0.0001 then return end if self.appliedCritMultFromArsenal > 0 then reduceCritMult(nil, hero, self.appliedCritMultFromArsenal) else addCritMult(nil, hero, -self.appliedCritMultFromArsenal) end self.appliedCritMultFromArsenal = 0 end function modifier_arsenal_dynamic_stats.prototype.applyBattleLevelFromTotals(self) local hero = self:GetParent() if not hero or not IsValidEntity(hero) or not hero:IsRealHero() then return end local bonus = math.max( 0, math.floor(self:getTotals().battle_level or 0) ) if bonus <= 0 then return end local targetLevel = 1 + bonus if hero:GetLevel() >= targetLevel then return end local prevAbilityPoints = hero:GetAbilityPoints() while hero:GetLevel() < targetLevel do hero:HeroLevelUp(false) hero:SetAbilityPoints(prevAbilityPoints) end end function modifier_arsenal_dynamic_stats.prototype.IsHidden(self) return true end function modifier_arsenal_dynamic_stats.prototype.IsPurgable(self) return false end function modifier_arsenal_dynamic_stats.prototype.RemoveOnDeath(self) return false end function modifier_arsenal_dynamic_stats.prototype.GetTexture(self) return "item_mantle" end function modifier_arsenal_dynamic_stats.prototype.DeclareFunctions(self) return { MODIFIER_PROPERTY_PREATTACK_BONUS_DAMAGE, MODIFIER_PROPERTY_ATTACKSPEED_BONUS_CONSTANT, MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS, MODIFIER_PROPERTY_HEALTH_BONUS, MODIFIER_PROPERTY_MANA_BONUS, MODIFIER_PROPERTY_HEALTH_REGEN_CONSTANT, MODIFIER_PROPERTY_MANA_REGEN_CONSTANT, MODIFIER_PROPERTY_MOVESPEED_BONUS_CONSTANT, MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS, MODIFIER_PROPERTY_SPELL_AMPLIFY_PERCENTAGE, MODIFIER_PROPERTY_STATS_STRENGTH_BONUS, MODIFIER_PROPERTY_STATS_AGILITY_BONUS, MODIFIER_PROPERTY_STATS_INTELLECT_BONUS, MODIFIER_PROPERTY_DAMAGEOUTGOING_PERCENTAGE, MODIFIER_PROPERTY_ATTACKSPEED_PERCENTAGE, MODIFIER_PROPERTY_MOVESPEED_BONUS_PERCENTAGE, MODIFIER_PROPERTY_BASEDAMAGEOUTGOING_PERCENTAGE } end function modifier_arsenal_dynamic_stats.prototype.getTotals(self) if IsServer() then local parent = self:GetParent() return coerceTotals( nil, getArsenalTotals(nil, parent) ) end return self.totals end function modifier_arsenal_dynamic_stats.prototype.GetModifierPreAttack_BonusDamage(self) return self:getTotals().bonus_damage end function modifier_arsenal_dynamic_stats.prototype.GetModifierAttackSpeedBonus_Constant(self) return self:getTotals().attack_speed end function modifier_arsenal_dynamic_stats.prototype.GetModifierPhysicalArmorBonus(self) return self:getTotals().bonus_armor end function modifier_arsenal_dynamic_stats.prototype.GetModifierHealthBonus(self) return self:getTotals().max_health end function modifier_arsenal_dynamic_stats.prototype.GetModifierManaBonus(self) return self:getTotals().max_mana end function modifier_arsenal_dynamic_stats.prototype.GetModifierConstantHealthRegen(self) return self:getTotals().health_regen end function modifier_arsenal_dynamic_stats.prototype.GetModifierConstantManaRegen(self) return self:getTotals().mana_regen end function modifier_arsenal_dynamic_stats.prototype.GetModifierMoveSpeedBonus_Constant(self) return self:getTotals().move_speed end function modifier_arsenal_dynamic_stats.prototype.GetModifierMagicalResistanceBonus(self) return self:getTotals().magic_resist end function modifier_arsenal_dynamic_stats.prototype.GetModifierSpellAmplify_Percentage(self) return self:getTotals().spell_amp end function modifier_arsenal_dynamic_stats.prototype.GetModifierBonusStats_Strength(self) local t = self:getTotals() return t.all_stats + t.bonus_strength end function modifier_arsenal_dynamic_stats.prototype.GetModifierBonusStats_Agility(self) local t = self:getTotals() return t.all_stats + t.bonus_agility end function modifier_arsenal_dynamic_stats.prototype.GetModifierBonusStats_Intellect(self) local t = self:getTotals() return t.all_stats + t.bonus_intellect end function modifier_arsenal_dynamic_stats.prototype.GetModifierDamageOutgoing_Percentage(self) return self:getTotals().outgoing_damage_pct end function modifier_arsenal_dynamic_stats.prototype.GetModifierAttackSpeedPercentage(self) return self:getTotals().attack_speed_pct end function modifier_arsenal_dynamic_stats.prototype.GetModifierMoveSpeedBonus_Percentage(self) return self:getTotals().move_speed_pct end function modifier_arsenal_dynamic_stats.prototype.GetModifierBaseDamageOutgoing_Percentage(self) return self:getTotals().base_damage_pct end modifier_arsenal_dynamic_stats = __TS__Decorate( modifier_arsenal_dynamic_stats, modifier_arsenal_dynamic_stats, {registerModifier(nil)}, {kind = "class", name = "modifier_arsenal_dynamic_stats"} ) ____exports.modifier_arsenal_dynamic_stats = modifier_arsenal_dynamic_stats return ____exports