local ____lualib = require("lualib_bundle") 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 ____CardSystem = require("cards.CardSystem") local CardBase = ____CardSystem.CardBase local RegisterCard = ____CardSystem.RegisterCard local ____CardBaseModifier = require("cards.CardBaseModifier") local CardBaseModifier = ____CardBaseModifier.CardBaseModifier local ____dota_ts_adapter = require("lib.dota_ts_adapter") local registerModifier = ____dota_ts_adapter.registerModifier local ____modifier_general_fired = require("abilities.modifiers.modifier_general_fired") local modifier_general_fired = ____modifier_general_fired.modifier_general_fired local ____luck = require("utils.luck") local rollLuckChance = ____luck.rollLuckChance local CARD_ID = 14 --- Общая глубина рикошета на герое: при нескольких копиях карты каждый modifier_card_14 — отдельный инстанс, иначе второй снова прокает от рикошетного удара. local sharedRicochetDepthByHero = {} local function getSharedCard14RicochetDepth(self, hero) return sharedRicochetDepthByHero[hero:entindex()] or 0 end local function addSharedCard14RicochetDepth(self, hero) local k = hero:entindex() sharedRicochetDepthByHero[k] = (sharedRicochetDepthByHero[k] or 0) + 1 end local function removeSharedCard14RicochetDepth(self, hero) local k = hero:entindex() local next = (sharedRicochetDepthByHero[k] or 1) - 1 if next <= 0 then __TS__Delete(sharedRicochetDepthByHero, k) else sharedRicochetDepthByHero[k] = next end end ____exports.card_14 = __TS__Class() local card_14 = ____exports.card_14 card_14.name = "card_14" card_14.____file_path = "scripts/vscripts/cards/examples/card_14.lua" __TS__ClassExtends(card_14, CardBase) function card_14.prototype.GetModifierName(self) return "modifier_card_14" end card_14 = __TS__Decorate(card_14, card_14, {RegisterCard}, {kind = "class", name = "card_14"}) ____exports.card_14 = card_14 ____exports.modifier_card_14 = __TS__Class() local modifier_card_14 = ____exports.modifier_card_14 modifier_card_14.name = "modifier_card_14" modifier_card_14.____file_path = "scripts/vscripts/cards/examples/card_14.lua" __TS__ClassExtends(modifier_card_14, CardBaseModifier) function modifier_card_14.prototype.____constructor(self, ...) CardBaseModifier.prototype.____constructor(self, ...) self.ricochetProjectile = self:GetParent():GetRangedProjectileName() or "" self.ricochetAttackDepth = 0 self.forcedRicochetDamagePct = 0 end function modifier_card_14.prototype.DeclareFunctions(self) return {MODIFIER_EVENT_ON_ATTACK_LANDED, MODIFIER_PROPERTY_DAMAGEOUTGOING_PERCENTAGE, MODIFIER_PROPERTY_TOOLTIP} end function modifier_card_14.prototype.getValue(self, key, fallback) return self:getCardValue(key, fallback, CARD_ID) end function modifier_card_14.prototype.addFiredStacks(self, target, attacker, stacks) if stacks <= 0 then return end local firedModifier = target:AddNewModifier( attacker, getModifierSourceAbility(nil, attacker), modifier_general_fired.name, {} ) if not firedModifier then return end do local i = 0 while i < stacks do firedModifier:IncrementStackCount() i = i + 1 end end end function modifier_card_14.prototype.GetModifierDamageOutgoing_Percentage(self) if self.ricochetAttackDepth <= 0 then return 0 end return self.forcedRicochetDamagePct end function modifier_card_14.prototype.performRicochetAttack(self, attacker, target, damagePct, burnStacks) if not attacker:IsAlive() or not target:IsAlive() then return end addSharedCard14RicochetDepth(nil, attacker) self.ricochetAttackDepth = self.ricochetAttackDepth + 1 self.forcedRicochetDamagePct = damagePct - 100 attacker:PerformAttack( target, true, true, true, false, false, false, true ) self.forcedRicochetDamagePct = 0 self.ricochetAttackDepth = math.max(0, self.ricochetAttackDepth - 1) removeSharedCard14RicochetDepth(nil, attacker) self:addFiredStacks(target, attacker, burnStacks) end function modifier_card_14.prototype.OnAttackLanded(self, event) if not IsServer() then return end if self.ricochetAttackDepth > 0 then return end local attacker = self:GetParent() if not attacker or not IsValidEntity(attacker) or event.attacker ~= attacker then return end if getSharedCard14RicochetDepth(nil, attacker) > 0 then return end local target = event.target if not target or not IsValidEntity(target) or not target:IsAlive() then return end if target:GetTeamNumber() == attacker:GetTeamNumber() then return end local copies = self:getCardCopies() local chancePct = math.min( 100, self:getValue("proc_chance_pct", 22) * copies ) local ____attacker_IsRealHero_result_0 if attacker:IsRealHero() then ____attacker_IsRealHero_result_0 = rollLuckChance(nil, attacker, chancePct / 100) else ____attacker_IsRealHero_result_0 = RollPercentage(chancePct) end local proc = ____attacker_IsRealHero_result_0 if not proc then return end local attackDamage = attacker:GetAverageTrueAttackDamage(target) if attackDamage <= 0 then return end local burnStacks = self:getValue("fired_stacks", 3) * copies local mainBonusPct = self:getValue("main_target_bonus_damage_pct", 35) * copies local mainDamage = attackDamage * (mainBonusPct / 100) if mainDamage > 0 then ApplyDamage({victim = target, attacker = attacker, damage = mainDamage, damage_type = DAMAGE_TYPE_MAGICAL}) end self:addFiredStacks(target, attacker, burnStacks) local radius = self:getValue("ricochet_radius", 300) local splashPct = self:getValue("ricochet_damage_pct", 60) * copies if splashPct <= 0 or radius <= 0 then return end local enemies = FindUnitsInRadius( attacker:GetTeamNumber(), target:GetAbsOrigin(), nil, radius, DOTA_UNIT_TARGET_TEAM_ENEMY, bit.bor(DOTA_UNIT_TARGET_HERO, DOTA_UNIT_TARGET_BASIC), DOTA_UNIT_TARGET_FLAG_NONE, FIND_ANY_ORDER, false ) local projectileSpeed = math.max( 700, attacker:GetProjectileSpeed() ) for ____, enemy in ipairs(enemies) do do if enemy == target then goto __continue29 end if not enemy:IsAlive() then goto __continue29 end local distance = (enemy:GetAbsOrigin() - target:GetAbsOrigin()):Length2D() local travelTime = projectileSpeed > 0 and distance / projectileSpeed or 0 ProjectileManager:CreateTrackingProjectile({ Source = target, Target = enemy, Ability = nil, EffectName = self.ricochetProjectile, iMoveSpeed = projectileSpeed, bDodgeable = true, bVisibleToEnemies = true, bReplaceExisting = false, bProvidesVision = false }) Timers:CreateTimer( travelTime, function() if not IsServer() then return nil end if not attacker:IsAlive() or not enemy:IsAlive() then return nil end self:performRicochetAttack(attacker, enemy, splashPct, burnStacks) return nil end ) end ::__continue29:: end end modifier_card_14 = __TS__Decorate( modifier_card_14, modifier_card_14, {registerModifier(nil)}, {kind = "class", name = "modifier_card_14"} ) ____exports.modifier_card_14 = modifier_card_14 return ____exports