Files
Dota-Zombie-Invasion/scripts/vscripts/cards/examples/card_14.lua
T
2026-05-29 15:11:31 +07:00

226 lines
8.1 KiB
Lua

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