Files
Dota-Zombie-Invasion/scripts/vscripts/abilities/creep/contract_head_leap.lua
T
2026-05-29 15:11:31 +07:00

469 lines
18 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local __TS__ClassExtends = ____lualib.__TS__ClassExtends
local __TS__Decorate = ____lualib.__TS__Decorate
local ____exports = {}
local ____difficulty_manager = require("difficulty_manager")
local Difficulty = ____difficulty_manager.Difficulty
local ____dota_ts_adapter = require("lib.dota_ts_adapter")
local BaseAbility = ____dota_ts_adapter.BaseAbility
local BaseModifier = ____dota_ts_adapter.BaseModifier
local BaseModifierMotionBoth = ____dota_ts_adapter.BaseModifierMotionBoth
local registerAbility = ____dota_ts_adapter.registerAbility
local registerModifier = ____dota_ts_adapter.registerModifier
--- Та же физика дуги, что у `frogmen_acid_jump` / `modifier_acid_blob_jump`.
local CONTRACT_HEAD_LEAP_MIN_HEIGHT_ABOVE_LOWEST = 400
local CONTRACT_HEAD_LEAP_MIN_HEIGHT_ABOVE_HIGHEST = 200
local CONTRACT_HEAD_LEAP_ACCELERATION_Z = 1500
local CONTRACT_HEAD_LEAP_MAX_HORIZONTAL_ACCELERATION = 1500
--- Пассивка контракта: прыжок дугой к точке, где стоял герой; урон только если к моменту приземления он не ушёл из зоны.
____exports.contract_head_leap = __TS__Class()
local contract_head_leap = ____exports.contract_head_leap
contract_head_leap.name = "contract_head_leap"
contract_head_leap.____file_path = "scripts/vscripts/abilities/creep/contract_head_leap.lua"
__TS__ClassExtends(contract_head_leap, BaseAbility)
function contract_head_leap.prototype.Precache(self, context)
PrecacheResource("particle", "particles/generic_gameplay/generic_hit_blood.vpcf", context)
PrecacheResource("particle", "particles/econ/events/darkmoon_2017/darkmoon_generic_aoe.vpcf", context)
PrecacheResource("particle", "particles/econ/events/darkmoon_2017/darkmoon_calldown_marker_arrows.vpcf", context)
end
function contract_head_leap.prototype.GetIntrinsicModifierName(self)
return "modifier_contract_head_leap_passive"
end
function contract_head_leap.prototype.showLeapPrecastVisuals(self, caster, strikeGround, damageRadius, warningDuration)
if not IsServer() or warningDuration <= 0 then
return
end
local groundPos = GetGroundPosition(strikeGround, nil)
local r = math.max(1, damageRadius)
local particleAoe = ParticleManager:CreateParticle("particles/econ/events/darkmoon_2017/darkmoon_generic_aoe.vpcf", PATTACH_CUSTOMORIGIN, nil)
if particleAoe ~= nil then
ParticleManager:SetParticleControl(particleAoe, 0, groundPos)
ParticleManager:SetParticleControl(
particleAoe,
1,
Vector(r, 0, 0)
)
ParticleManager:SetParticleControl(
particleAoe,
2,
Vector(6, 0, 1)
)
ParticleManager:SetParticleControl(
particleAoe,
3,
Vector(200, 0, 0)
)
ParticleManager:SetParticleControl(particleAoe, 4, groundPos)
Timers:CreateTimer(
warningDuration,
function()
ParticleManager:DestroyParticle(particleAoe, false)
ParticleManager:ReleaseParticleIndex(particleAoe)
end
)
end
local casterPos = GetGroundPosition(
caster:GetAbsOrigin(),
nil
)
local particleArrow = ParticleManager:CreateParticle("particles/econ/events/darkmoon_2017/darkmoon_calldown_marker_arrows.vpcf", PATTACH_CUSTOMORIGIN, nil)
if particleArrow ~= nil then
ParticleManager:SetParticleControl(particleArrow, 0, casterPos)
ParticleManager:SetParticleControl(particleArrow, 1, groundPos)
ParticleManager:SetParticleControl(
particleArrow,
2,
Vector(warningDuration, 0, 0)
)
Timers:CreateTimer(
warningDuration,
function()
ParticleManager:DestroyParticle(particleArrow, false)
ParticleManager:ReleaseParticleIndex(particleArrow)
end
)
end
end
function contract_head_leap.prototype.performLeapLanding(self, heroEntIndex, strikeGround)
if not IsServer() then
return
end
local creep = self:GetCaster()
if not creep or not IsValidEntity(creep) or not creep:IsAlive() then
return
end
local hero = EntIndexToHScript(heroEntIndex)
local hitRadius = math.max(
0,
self:GetSpecialValueFor("damage_radius")
)
local hpos = hero and IsValidEntity(hero) and hero:IsAlive() and hero:GetAbsOrigin() or nil
local inZone = false
if hpos ~= nil then
local dx = hpos.x - strikeGround.x
local dy = hpos.y - strikeGround.y
inZone = math.sqrt(dx * dx + dy * dy) <= hitRadius
end
if hero and IsValidEntity(hero) and hero:IsAlive() and not hero:IsInvulnerable() and inZone then
local scale = Difficulty:getNpcStatScale()
local flatDamage = math.max(
1,
math.floor(self:GetSpecialValueFor("leap_damage") * scale + 0.5)
)
local pctFromAttack = math.max(
0,
self:GetSpecialValueFor("damage_from_attack_pct")
)
local avgAtk = creep:GetAverageTrueAttackDamage(hero)
local fromAttack = math.floor(avgAtk * (pctFromAttack / 100) * scale + 0.5)
local totalDamage = flatDamage + fromAttack
ApplyDamage({
victim = hero,
attacker = creep,
damage = totalDamage,
damage_type = DAMAGE_TYPE_PHYSICAL,
ability = self
})
local hitFx = ParticleManager:CreateParticle("particles/generic_gameplay/generic_hit_blood.vpcf", PATTACH_CUSTOMORIGIN, nil)
ParticleManager:SetParticleControlEnt(
hitFx,
0,
hero,
PATTACH_POINT_FOLLOW,
"attach_hitloc",
hero:GetAbsOrigin(),
true
)
ParticleManager:ReleaseParticleIndex(hitFx)
EmitSoundOn("Hero_MonkeyKing.Spring.Channel", creep)
end
end
contract_head_leap = __TS__Decorate(
contract_head_leap,
contract_head_leap,
{registerAbility(nil)},
{kind = "class", name = "contract_head_leap"}
)
____exports.contract_head_leap = contract_head_leap
____exports.modifier_contract_head_leap_passive = __TS__Class()
local modifier_contract_head_leap_passive = ____exports.modifier_contract_head_leap_passive
modifier_contract_head_leap_passive.name = "modifier_contract_head_leap_passive"
modifier_contract_head_leap_passive.____file_path = "scripts/vscripts/abilities/creep/contract_head_leap.lua"
__TS__ClassExtends(modifier_contract_head_leap_passive, BaseModifier)
function modifier_contract_head_leap_passive.prototype.____constructor(self, ...)
BaseModifier.prototype.____constructor(self, ...)
self.precastLockUntil = -1
end
function modifier_contract_head_leap_passive.prototype.IsHidden(self)
return true
end
function modifier_contract_head_leap_passive.prototype.IsDebuff(self)
return false
end
function modifier_contract_head_leap_passive.prototype.IsPurgable(self)
return false
end
function modifier_contract_head_leap_passive.prototype.OnCreated(self)
if not IsServer() then
return
end
local ability = self:GetAbility()
local interval = ability and math.max(
0.35,
ability:GetSpecialValueFor("leap_interval")
) or 2.4
self:StartIntervalThink(interval)
end
function modifier_contract_head_leap_passive.prototype.OnRefresh(self)
if not IsServer() then
return
end
local ability = self:GetAbility()
local interval = ability and math.max(
0.35,
ability:GetSpecialValueFor("leap_interval")
) or 2.4
self:StartIntervalThink(interval)
end
function modifier_contract_head_leap_passive.prototype.OnIntervalThink(self)
if not IsServer() then
return
end
local parent = self:GetParent()
local ability = self:GetAbility()
if not ability or not IsValidEntity(parent) or not parent:IsAlive() or parent:IsStunned() or parent:IsHexed() then
return
end
local now = GameRules:GetDOTATime(false, false)
if now < self.precastLockUntil then
return
end
local primary = parent:FindAbilityByName("contract_head_leap")
if not primary or primary ~= ability then
return
end
if parent:HasModifier("modifier_contract_head_leap_arc") then
return
end
local radius = math.max(
50,
ability:GetSpecialValueFor("search_radius")
)
local heroes = FindUnitsInRadius(
parent:GetTeamNumber(),
parent:GetAbsOrigin(),
nil,
radius,
DOTA_UNIT_TARGET_TEAM_ENEMY,
DOTA_UNIT_TARGET_HERO,
DOTA_UNIT_TARGET_FLAG_NONE,
FIND_CLOSEST,
false
)
local hero
for ____, u in ipairs(heroes) do
do
if not u or not IsValidEntity(u) or not u:IsAlive() or not u:IsHero() then
goto __continue28
end
if not u:IsRealHero() then
goto __continue28
end
if u:IsInvulnerable() then
goto __continue28
end
if u:GetUnitName() == "npc_homer" then
goto __continue28
end
hero = u
break
end
::__continue28::
end
if not hero then
return
end
local height = math.max(
40,
ability:GetSpecialValueFor("height_above_hero")
)
local strikeGround = GetGroundPosition(
hero:GetAbsOrigin(),
hero
)
local headPos = Vector(strikeGround.x, strikeGround.y, strikeGround.z + height)
local warningTime = math.max(
0,
ability:GetSpecialValueFor("precast_warning_time")
)
local dmgRadius = math.max(
1,
ability:GetSpecialValueFor("damage_radius")
)
local arcPayload = {
vLocX = headPos.x,
vLocY = headPos.y,
vLocZ = headPos.z,
strikeX = strikeGround.x,
strikeY = strikeGround.y,
strikeZ = strikeGround.z,
hero_ei = hero:entindex()
}
if warningTime > 0 then
self.precastLockUntil = now + warningTime
ability:showLeapPrecastVisuals(parent, strikeGround, dmgRadius, warningTime)
local ____self = self
Timers:CreateTimer(
warningTime,
function()
____self.precastLockUntil = -1
if not IsServer() then
return
end
if not IsValidEntity(parent) or not parent:IsAlive() then
return
end
if parent:HasModifier("modifier_contract_head_leap_arc") then
return
end
local ab = parent:FindAbilityByName("contract_head_leap")
if not ab then
return
end
parent:AddNewModifier(parent, ab, "modifier_contract_head_leap_arc", arcPayload)
end
)
else
parent:AddNewModifier(parent, ability, "modifier_contract_head_leap_arc", arcPayload)
end
end
modifier_contract_head_leap_passive = __TS__Decorate(
modifier_contract_head_leap_passive,
modifier_contract_head_leap_passive,
{registerModifier(nil)},
{kind = "class", name = "modifier_contract_head_leap_passive"}
)
____exports.modifier_contract_head_leap_passive = modifier_contract_head_leap_passive
____exports.modifier_contract_head_leap_arc = __TS__Class()
local modifier_contract_head_leap_arc = ____exports.modifier_contract_head_leap_arc
modifier_contract_head_leap_arc.name = "modifier_contract_head_leap_arc"
modifier_contract_head_leap_arc.____file_path = "scripts/vscripts/abilities/creep/contract_head_leap.lua"
__TS__ClassExtends(modifier_contract_head_leap_arc, BaseModifierMotionBoth)
function modifier_contract_head_leap_arc.prototype.____constructor(self, ...)
BaseModifierMotionBoth.prototype.____constructor(self, ...)
self.bHorizontalMotionInterrupted = false
self.flCurrentTimeHoriz = 0
self.flCurrentTimeVert = 0
self.flInitialVelocityZ = 0
self.flPredictedTotalTime = 0
end
function modifier_contract_head_leap_arc.prototype.IsHidden(self)
return true
end
function modifier_contract_head_leap_arc.prototype.IsPurgable(self)
return false
end
function modifier_contract_head_leap_arc.prototype.RemoveOnDeath(self)
return true
end
function modifier_contract_head_leap_arc.prototype.OnCreated(self, params)
if not IsServer() then
return
end
local parent = self:GetParent()
local ability = self:GetAbility()
if not parent or not ability then
self:Destroy()
return
end
local hx = params.hero_ei
if hx == nil or hx == nil then
self:Destroy()
return
end
self.heroEntIndex = hx
local sx = params.strikeX or parent:GetOrigin().x
local sy = params.strikeY or parent:GetOrigin().y
local sz = params.strikeZ or parent:GetOrigin().z
self.strikeGround = Vector(sx, sy, sz)
self.bHorizontalMotionInterrupted = false
if not self:ApplyHorizontalMotionController() or not self:ApplyVerticalMotionController() then
self:Destroy()
return
end
self.vStartPosition = GetGroundPosition(
parent:GetOrigin(),
parent
)
self.flCurrentTimeHoriz = 0
self.flCurrentTimeVert = 0
local x = params.vLocX or parent:GetOrigin().x
local y = params.vLocY or parent:GetOrigin().y
local z = params.vLocZ or parent:GetOrigin().z
self.vLoc = Vector(x, y, z)
self.vLastKnownTargetPos = self.vLoc
local duration = math.max(
0.08,
ability:GetSpecialValueFor("jump_duration")
)
local flDesiredHeight = CONTRACT_HEAD_LEAP_MIN_HEIGHT_ABOVE_LOWEST * duration * duration
local flLowZ = math.min(self.vLastKnownTargetPos.z, self.vStartPosition.z)
local flHighZ = math.max(self.vLastKnownTargetPos.z, self.vStartPosition.z)
local flArcTopZ = math.max(flLowZ + flDesiredHeight, flHighZ + CONTRACT_HEAD_LEAP_MIN_HEIGHT_ABOVE_HIGHEST)
local flArcDeltaZ = flArcTopZ - self.vStartPosition.z
self.flInitialVelocityZ = math.sqrt(2 * flArcDeltaZ * CONTRACT_HEAD_LEAP_ACCELERATION_Z)
local flDeltaZ = self.vLastKnownTargetPos.z - self.vStartPosition.z
local flSqrtDet = math.sqrt(math.max(0, self.flInitialVelocityZ * self.flInitialVelocityZ - 2 * CONTRACT_HEAD_LEAP_ACCELERATION_Z * flDeltaZ))
self.flPredictedTotalTime = math.max((self.flInitialVelocityZ + flSqrtDet) / CONTRACT_HEAD_LEAP_ACCELERATION_Z, (self.flInitialVelocityZ - flSqrtDet) / CONTRACT_HEAD_LEAP_ACCELERATION_Z)
self.vHorizontalVelocity = (self.vLastKnownTargetPos - self.vStartPosition) / self.flPredictedTotalTime
self.vHorizontalVelocity.z = 0
end
function modifier_contract_head_leap_arc.prototype.OnDestroy(self)
if not IsServer() then
return
end
local parent = self:GetParent()
if parent ~= nil then
parent:RemoveHorizontalMotionController(self)
parent:RemoveVerticalMotionController(self)
end
end
function modifier_contract_head_leap_arc.prototype.CheckState(self)
return {[MODIFIER_STATE_STUNNED] = true, [MODIFIER_STATE_UNSELECTABLE] = true}
end
function modifier_contract_head_leap_arc.prototype.UpdateHorizontalMotion(self, me, dt)
if not IsServer() then
return
end
self.flCurrentTimeHoriz = math.min(self.flCurrentTimeHoriz + dt, self.flPredictedTotalTime)
local t = self.flCurrentTimeHoriz / self.flPredictedTotalTime
local vStartToTarget = self.vLastKnownTargetPos - self.vStartPosition
local vDesiredPos = self.vStartPosition + vStartToTarget * t
local vOldPos = me:GetOrigin()
local vToDesired = vDesiredPos - vOldPos
vToDesired.z = 0
local vDesiredVel = vToDesired / dt
local vVelDif = vDesiredVel - self.vHorizontalVelocity
local flVelDif = vVelDif:Length2D()
vVelDif = vVelDif:Normalized()
local flVelDelta = math.min(flVelDif, CONTRACT_HEAD_LEAP_MAX_HORIZONTAL_ACCELERATION)
self.vHorizontalVelocity = self.vHorizontalVelocity + vVelDif * flVelDelta * dt
local vNewPos = vOldPos + self.vHorizontalVelocity * dt
me:SetOrigin(vNewPos)
end
function modifier_contract_head_leap_arc.prototype.UpdateVerticalMotion(self, me, dt)
if not IsServer() then
return
end
self.flCurrentTimeVert = self.flCurrentTimeVert + dt
local bGoingDown = -CONTRACT_HEAD_LEAP_ACCELERATION_Z * self.flCurrentTimeVert + self.flInitialVelocityZ < 0
local vNewPos = me:GetOrigin()
vNewPos.z = self.vStartPosition.z + (-0.5 * CONTRACT_HEAD_LEAP_ACCELERATION_Z * self.flCurrentTimeVert * self.flCurrentTimeVert + self.flInitialVelocityZ * self.flCurrentTimeVert)
local flGroundHeight = GetGroundHeight(
vNewPos,
self:GetParent()
)
local bLanded = false
if vNewPos.z < flGroundHeight and bGoingDown then
vNewPos.z = flGroundHeight
bLanded = true
end
me:SetOrigin(vNewPos)
if bLanded then
if not self.bHorizontalMotionInterrupted then
local ability = self:GetAbility()
if ability then
ability:performLeapLanding(self.heroEntIndex, self.strikeGround)
end
end
self:Destroy()
end
end
function modifier_contract_head_leap_arc.prototype.OnHorizontalMotionInterrupted(self)
if not IsServer() then
return
end
self.bHorizontalMotionInterrupted = true
end
function modifier_contract_head_leap_arc.prototype.OnVerticalMotionInterrupted(self)
if not IsServer() then
return
end
self:Destroy()
end
function modifier_contract_head_leap_arc.prototype.DeclareFunctions(self)
return {MODIFIER_PROPERTY_OVERRIDE_ANIMATION}
end
function modifier_contract_head_leap_arc.prototype.GetOverrideAnimation(self)
return ACT_DOTA_CAST_ABILITY_1
end
modifier_contract_head_leap_arc = __TS__Decorate(
modifier_contract_head_leap_arc,
modifier_contract_head_leap_arc,
{registerModifier(nil)},
{kind = "class", name = "modifier_contract_head_leap_arc"}
)
____exports.modifier_contract_head_leap_arc = modifier_contract_head_leap_arc
return ____exports