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

291 lines
11 KiB
Lua

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 ____dota_ts_adapter = require("lib.dota_ts_adapter")
local BaseAbility = ____dota_ts_adapter.BaseAbility
local BaseModifierMotionBoth = ____dota_ts_adapter.BaseModifierMotionBoth
local registerAbility = ____dota_ts_adapter.registerAbility
local registerModifier = ____dota_ts_adapter.registerModifier
____exports.frogmen_acid_jump = __TS__Class()
local frogmen_acid_jump = ____exports.frogmen_acid_jump
frogmen_acid_jump.name = "frogmen_acid_jump"
frogmen_acid_jump.____file_path = "scripts/vscripts/abilities/creep/frogmen_acid_jump.lua"
__TS__ClassExtends(frogmen_acid_jump, BaseAbility)
function frogmen_acid_jump.prototype.____constructor(self, ...)
BaseAbility.prototype.____constructor(self, ...)
self.radius = 0
self.stun_duration = 0
self.land_damage = 0
end
function frogmen_acid_jump.prototype.Precache(self, context)
PrecacheResource("particle", "particles/neutral_fx/ogre_bruiser_smash.vpcf", context)
end
function frogmen_acid_jump.prototype.OnAbilityPhaseStart(self)
if not IsServer() then
return true
end
return true
end
function frogmen_acid_jump.prototype.OnAbilityPhaseInterrupted(self)
if not IsServer() then
return
end
end
function frogmen_acid_jump.prototype.OnSpellStart(self)
if not IsServer() then
return
end
local caster = self:GetCaster()
if not caster then
return
end
local cursorPos = self:GetCursorPosition()
local kv = {vLocX = cursorPos.x, vLocY = cursorPos.y, vLocZ = cursorPos.z}
caster:AddNewModifier(caster, self, "modifier_acid_blob_jump", kv)
self.radius = self:GetSpecialValueFor("radius")
self.stun_duration = self:GetSpecialValueFor("stun_duration")
self.land_damage = self:GetSpecialValueFor("land_damage")
end
function frogmen_acid_jump.prototype.Smash(self)
if not IsServer() then
return
end
local caster = self:GetCaster()
if not caster then
return
end
local origin = caster:GetOrigin()
EmitSoundOnLocationWithCaster(origin, "OgreTank.GroundSmash", caster)
local smashFX = ParticleManager:CreateParticle("particles/neutral_fx/ogre_bruiser_smash.vpcf", PATTACH_WORLDORIGIN, caster)
ParticleManager:SetParticleControl(smashFX, 0, origin)
ParticleManager:SetParticleControl(
smashFX,
1,
Vector(self.radius, self.radius, self.radius)
)
ParticleManager:ReleaseParticleIndex(smashFX)
caster:Interrupt()
local enemies = FindUnitsInRadius(
caster:GetTeamNumber(),
origin,
caster,
self.radius,
DOTA_UNIT_TARGET_TEAM_ENEMY,
DOTA_UNIT_TARGET_HERO + DOTA_UNIT_TARGET_BASIC,
DOTA_UNIT_TARGET_FLAG_MAGIC_IMMUNE_ENEMIES,
FIND_ANY_ORDER,
false
)
for ____, enemy in ipairs(enemies) do
do
if not enemy then
goto __continue13
end
if enemy:IsInvulnerable() then
goto __continue13
end
ApplyDamage({
victim = enemy,
attacker = caster,
damage = self.land_damage + self:GetCaster():GetAverageTrueAttackDamage(enemy) * 2,
damage_type = DAMAGE_TYPE_PHYSICAL,
ability = self
})
if not enemy:IsAlive() then
local critFX = ParticleManager:CreateParticle("particles/units/heroes/hero_phantom_assassin/phantom_assassin_crit_impact.vpcf", PATTACH_CUSTOMORIGIN, nil)
ParticleManager:SetParticleControlEnt(
critFX,
0,
enemy,
PATTACH_POINT_FOLLOW,
"attach_hitloc",
enemy:GetOrigin(),
true
)
ParticleManager:SetParticleControl(
critFX,
1,
enemy:GetOrigin()
)
local forward = caster:GetForwardVector()
ParticleManager:SetParticleControlForward(critFX, 1, forward * -1)
ParticleManager:SetParticleControlEnt(
critFX,
10,
enemy,
PATTACH_ABSORIGIN_FOLLOW,
nil,
enemy:GetOrigin(),
true
)
ParticleManager:ReleaseParticleIndex(critFX)
EmitSoundOn("Dungeon.BloodSplatterImpact", enemy)
else
enemy:AddNewModifier(caster, self, "modifier_stunned", {duration = self.stun_duration})
end
end
::__continue13::
end
end
frogmen_acid_jump = __TS__Decorate(
frogmen_acid_jump,
frogmen_acid_jump,
{registerAbility(nil)},
{kind = "class", name = "frogmen_acid_jump"}
)
____exports.frogmen_acid_jump = frogmen_acid_jump
local AMOEBA_MINIMUM_HEIGHT_ABOVE_LOWEST = 400
local AMOEBA_MINIMUM_HEIGHT_ABOVE_HIGHEST = 200
local AMOEBA_ACCELERATION_Z = 1500
local AMOEBA_MAX_HORIZONTAL_ACCELERATION = 1500
____exports.modifier_acid_blob_jump = __TS__Class()
local modifier_acid_blob_jump = ____exports.modifier_acid_blob_jump
modifier_acid_blob_jump.name = "modifier_acid_blob_jump"
modifier_acid_blob_jump.____file_path = "scripts/vscripts/abilities/creep/frogmen_acid_jump.lua"
__TS__ClassExtends(modifier_acid_blob_jump, BaseModifierMotionBoth)
function modifier_acid_blob_jump.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_acid_blob_jump.prototype.IsHidden(self)
return true
end
function modifier_acid_blob_jump.prototype.IsPurgable(self)
return false
end
function modifier_acid_blob_jump.prototype.RemoveOnDeath(self)
return false
end
function modifier_acid_blob_jump.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
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 = ability:GetSpecialValueFor("duration")
local flDesiredHeight = AMOEBA_MINIMUM_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 + AMOEBA_MINIMUM_HEIGHT_ABOVE_HIGHEST)
local flArcDeltaZ = flArcTopZ - self.vStartPosition.z
self.flInitialVelocityZ = math.sqrt(2 * flArcDeltaZ * AMOEBA_ACCELERATION_Z)
local flDeltaZ = self.vLastKnownTargetPos.z - self.vStartPosition.z
local flSqrtDet = math.sqrt(math.max(0, self.flInitialVelocityZ * self.flInitialVelocityZ - 2 * AMOEBA_ACCELERATION_Z * flDeltaZ))
self.flPredictedTotalTime = math.max((self.flInitialVelocityZ + flSqrtDet) / AMOEBA_ACCELERATION_Z, (self.flInitialVelocityZ - flSqrtDet) / AMOEBA_ACCELERATION_Z)
self.vHorizontalVelocity = (self.vLastKnownTargetPos - self.vStartPosition) / self.flPredictedTotalTime
self.vHorizontalVelocity.z = 0
end
function modifier_acid_blob_jump.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_acid_blob_jump.prototype.CheckState(self)
return {[MODIFIER_STATE_STUNNED] = true, [MODIFIER_STATE_UNSELECTABLE] = true}
end
function modifier_acid_blob_jump.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, AMOEBA_MAX_HORIZONTAL_ACCELERATION)
self.vHorizontalVelocity = self.vHorizontalVelocity + vVelDif * flVelDelta * dt
local vNewPos = vOldPos + self.vHorizontalVelocity * dt
me:SetOrigin(vNewPos)
end
function modifier_acid_blob_jump.prototype.UpdateVerticalMotion(self, me, dt)
if not IsServer() then
return
end
self.flCurrentTimeVert = self.flCurrentTimeVert + dt
local bGoingDown = -AMOEBA_ACCELERATION_Z * self.flCurrentTimeVert + self.flInitialVelocityZ < 0
local vNewPos = me:GetOrigin()
vNewPos.z = self.vStartPosition.z + (-0.5 * AMOEBA_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:Smash()
end
end
self:Destroy()
end
end
function modifier_acid_blob_jump.prototype.OnHorizontalMotionInterrupted(self)
if not IsServer() then
return
end
self.bHorizontalMotionInterrupted = true
end
function modifier_acid_blob_jump.prototype.OnVerticalMotionInterrupted(self)
if not IsServer() then
return
end
self:Destroy()
end
function modifier_acid_blob_jump.prototype.DeclareFunctions(self)
return {MODIFIER_PROPERTY_OVERRIDE_ANIMATION}
end
function modifier_acid_blob_jump.prototype.GetOverrideAnimation(self)
return ACT_DOTA_CAST_ABILITY_1
end
modifier_acid_blob_jump = __TS__Decorate(
modifier_acid_blob_jump,
modifier_acid_blob_jump,
{registerModifier(nil)},
{kind = "class", name = "modifier_acid_blob_jump"}
)
____exports.modifier_acid_blob_jump = modifier_acid_blob_jump
return ____exports