326 lines
12 KiB
Lua
Executable File
326 lines
12 KiB
Lua
Executable File
aghanim_shard_attack = class( {} )
|
|
|
|
LinkLuaModifier( "modifier_aghanim_shard_attack", "modifiers/creatures/modifier_aghanim_shard_attack", LUA_MODIFIER_MOTION_NONE )
|
|
|
|
_G.PATTERN_SPIRAL = 0
|
|
_G.PATTERN_REBOUND = 1
|
|
_G.PATTERN_JITTER = 2
|
|
_G.CAST_ESCLATION_PCT = 17
|
|
|
|
_G.FAST_COLOR = Vector( 0, 0, 255 )
|
|
_G.SLOW_COLOR = Vector( 350, 0, 0 ) -- looks weird, but it's because it can't go to 0 speed
|
|
_G.HEAL_COLOR = Vector( 0, 255, 0 )
|
|
|
|
----------------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:Precache( context )
|
|
PrecacheResource( "particle", "particles/creatures/aghanim/aghanim_shard_channel.vpcf", context )
|
|
PrecacheResource( "particle", "particles/creatures/aghanim/aghanim_shard_proj.vpcf", context )
|
|
PrecacheResource( "particle", "particles/units/heroes/hero_lich/lich_frost_nova.vpcf", context )
|
|
PrecacheResource( "soundfile", "soundevents/game_sounds_heroes/game_sounds_dark_willow.vsndevts", context )
|
|
PrecacheResource( "soundfile", "soundevents/game_sounds_heroes/game_sounds_silencer.vsndevts", context )
|
|
|
|
self.nPattern = PATTERN_SPIRAL
|
|
self.nCastCount = 0
|
|
self.Projectiles = {}
|
|
end
|
|
|
|
----------------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:ProcsMagicStick()
|
|
return false
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:OnAbilityPhaseStart()
|
|
if IsServer() then
|
|
StartSoundEventFromPositionReliable( "Aghanim.ShardAttack.Channel", self:GetCaster():GetAbsOrigin() )
|
|
self.nChannelFX = ParticleManager:CreateParticle( "particles/creatures/aghanim/aghanim_shard_channel.vpcf", PATTACH_ABSORIGIN_FOLLOW, self:GetCaster() )
|
|
end
|
|
return true
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:OnChannelThink( flInterval )
|
|
if IsServer() then
|
|
if self.nPattern == PATTERN_SPIRAL then
|
|
self:ThinkSpirals( flInterval )
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:OnChannelFinish( bInterrupted )
|
|
if IsServer() then
|
|
StopSoundOn( "Aghanim.ShardAttack.Loop", self:GetCaster() )
|
|
ParticleManager:DestroyParticle( self.nChannelFX, false )
|
|
self.nCastCount = self.nCastCount + 1
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:OnSpellStart()
|
|
if IsServer() then
|
|
EmitSoundOn( "Aghanim.ShardAttack.Loop", self:GetCaster() )
|
|
if self.nPattern == PATTERN_SPIRAL then
|
|
self:BeginSpirals()
|
|
end
|
|
if self.nPattern == PATTERN_REBOUND then
|
|
self:BeginRebound()
|
|
end
|
|
if self.nPattern == PATTERN_JITTER then
|
|
self:BeginJitter()
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:BeginSpirals()
|
|
self.Projectiles = {}
|
|
|
|
self.spiral_projectiles = self:GetSpecialValueFor( "spiral_projectiles" )
|
|
self.spiral_projectile_waves = self:GetSpecialValueFor( "spiral_projectile_waves" )
|
|
self.spiral_projectile_speed = self:GetSpecialValueFor( "spiral_projectile_speed" )
|
|
|
|
self.spiral_projectiles = math.min( self.spiral_projectiles * 2, math.floor( self.spiral_projectiles + ( self.spiral_projectiles * CAST_ESCLATION_PCT * self.nCastCount / 100 ) ) )
|
|
self.spiral_projectile_waves = math.min( self.spiral_projectile_waves * 2, math.floor( self.spiral_projectile_waves + ( self.spiral_projectile_waves * CAST_ESCLATION_PCT * self.nCastCount / 100 ) ) )
|
|
self.spiral_projectile_speed = math.min( self.spiral_projectile_speed * 2, math.floor( self.spiral_projectile_speed + ( self.spiral_projectile_speed * CAST_ESCLATION_PCT * self.nCastCount / 100 ) ) )
|
|
|
|
self.spiral_projectile_rotation_speed = self:GetSpecialValueFor( "spiral_projectile_rotation_speed" )
|
|
self.spiral_projectile_width = self:GetSpecialValueFor( "spiral_projectile_width" )
|
|
self.spiral_projectile_damage = self:GetSpecialValueFor( "spiral_projectile_damage" )
|
|
self.spiral_projectile_speed_change_interval = self:GetSpecialValueFor( "spiral_projectile_speed_change_interval" )
|
|
|
|
self.flSpiralYaw = RandomInt( 0, 360 )
|
|
self.flSpiralWaveInterval = self:GetChannelTime() / self.spiral_projectile_waves
|
|
self.flSpiralNextWaveTime = GameRules:GetGameTime()
|
|
self.flSpiralYawStep = 360 / self.spiral_projectiles
|
|
self.bReverse = false
|
|
|
|
if RandomInt( 0, 1 ) == 1 then
|
|
self.bReverse = true
|
|
end
|
|
|
|
self.flSpiralSpeedToggleTime = GameRules:GetGameTime() + self.spiral_projectile_speed_change_interval
|
|
self.bSpiralSpeedingUp = true
|
|
self.flCurSpeed = self.spiral_projectile_speed
|
|
self.nToggleCount = 0
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:ThinkSpirals( flInterval )
|
|
local flNow = GameRules:GetGameTime()
|
|
if flNow > self.flSpiralSpeedToggleTime then
|
|
self.flSpiralSpeedToggleTime = flNow + self.spiral_projectile_speed_change_interval
|
|
self.bSpiralSpeedingUp = not self.bSpiralSpeedingUp
|
|
self.nToggleCount = self.nToggleCount + 1
|
|
if self.nToggleCount == 2 then
|
|
self.bReverse = not self.bReverse
|
|
self.nToggleCount = 0
|
|
end
|
|
end
|
|
|
|
local flRate = ( self.spiral_projectile_speed / self.spiral_projectile_speed_change_interval ) * flInterval
|
|
if self.bSpiralSpeedingUp then
|
|
self.flCurSpeed = math.min( self.spiral_projectile_speed, self.flCurSpeed + flRate )
|
|
else
|
|
self.flCurSpeed = math.max( 100, self.flCurSpeed - flRate )
|
|
end
|
|
|
|
if self.flSpiralNextWaveTime > flNow then
|
|
return
|
|
end
|
|
|
|
self.flSpiralNextWaveTime = flNow + self.flSpiralWaveInterval
|
|
EmitSoundOn( "Aghanim.ShardAttack.Wave", self:GetCaster() )
|
|
|
|
for i=1,self.spiral_projectiles do
|
|
local Angle = QAngle( 0, self.flSpiralYaw, 0 )
|
|
local vVelocity = ( RotatePosition( Vector( 0, 0, 0 ), Angle, Vector( 1, 0, 0 ) ) ) * self.flCurSpeed
|
|
local nProjectileHandle = self:LaunchCrystals( vVelocity, 5000, self.spiral_projectile_width )
|
|
|
|
local ProjectileInfo = {}
|
|
ProjectileInfo.nHandle = nProjectileHandle
|
|
ProjectileInfo.flYaw = self.flSpiralYaw
|
|
ProjectileInfo.nFXIndex = ParticleManager:CreateParticle( "particles/creatures/aghanim/aghanim_shard_proj.vpcf", PATTACH_CUSTOMORIGIN, nil )
|
|
|
|
local vLoc = self:GetCaster():GetAbsOrigin()
|
|
vLoc.z = GetGroundHeight( vLoc, self:GetCaster() ) + 50
|
|
ProjectileInfo.attachEnt = CreateUnitByName( "npc_dota_wisp_spirit", vLoc, false, self:GetCaster(), self:GetCaster(), DOTA_TEAM_GOODGUYS )
|
|
if ProjectileInfo.attachEnt ~= nil then
|
|
ProjectileInfo.attachEnt:AddNewModifier( self:GetCaster(), self, "modifier_wisp_spirit_invulnerable", {} )
|
|
end
|
|
ParticleManager:SetParticleControlEnt( ProjectileInfo.nFXIndex, 0, ProjectileInfo.attachEnt, PATTACH_ABSORIGIN_FOLLOW, nil, vLoc, false )
|
|
ParticleManager:SetParticleControl( ProjectileInfo.nFXIndex, 1, Vector( self.spiral_projectile_width, self.spiral_projectile_width, self.spiral_projectile_width ) )
|
|
ParticleManager:SetParticleControl( ProjectileInfo.nFXIndex, 2, Vector( 6, 6, 6 ) )
|
|
|
|
--local flSpeedColorFactor = self.flCurSpeed / self.spiral_projectile_speed
|
|
--local vColor = LerpVectors( SLOW_COLOR, FAST_COLOR, flSpeedColorFactor )
|
|
--ParticleManager:SetParticleControl( ProjectileInfo.nFXIndex, 15, vColor )
|
|
|
|
table.insert( self.Projectiles, ProjectileInfo )
|
|
|
|
if self.bReverse then
|
|
self.flSpiralYaw = self.flSpiralYaw - self.flSpiralYawStep
|
|
else
|
|
self.flSpiralYaw = self.flSpiralYaw + self.flSpiralYawStep
|
|
end
|
|
end
|
|
|
|
self.flSpiralYaw = self.flSpiralYaw + self.flSpiralYawStep * 0.5
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:ThinkSpiralProjectile( info )
|
|
if self:IsChanneling() then
|
|
local flNewYaw = 0
|
|
if self.bReverse then
|
|
flNewYaw = info.flYaw - self.spiral_projectile_rotation_speed
|
|
else
|
|
flNewYaw = info.flYaw + self.spiral_projectile_rotation_speed
|
|
end
|
|
|
|
info.flYaw = flNewYaw
|
|
|
|
local Angle = QAngle( 0, flNewYaw, 0 )
|
|
local vNewVelocity = ( RotatePosition( Vector( 0, 0, 0 ), Angle, Vector( 1, 0, 0 ) ) ) * self.flCurSpeed
|
|
ProjectileManager:UpdateLinearProjectileDirection( info.nHandle, vNewVelocity, 5000 )
|
|
end
|
|
|
|
|
|
local vLoc = ProjectileManager:GetLinearProjectileLocation( info.nHandle )
|
|
vLoc.z = GetGroundHeight( vLoc, self:GetCaster() ) + 50
|
|
info.attachEnt:SetAbsOrigin( vLoc )
|
|
--ParticleManager:SetParticleControl( info.nFXIndex, 0, vLoc )
|
|
|
|
--local flSpeedColorFactor = self.flCurSpeed / self.spiral_projectile_speed
|
|
--local vColor = LerpVectors( SLOW_COLOR, FAST_COLOR, flSpeedColorFactor )
|
|
--ParticleManager:SetParticleControl( info.nFXIndex, 15, vColor )
|
|
|
|
--rint( "setting new velocity on spiral projectile" )
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:BeginRebound()
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:ThinkRebound( flInterval )
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:ThinkReboundProjectile( info )
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:BeginJitter()
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:ThinkJitter( flInterval )
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:ThinkJitterProjectile( info )
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:LaunchCrystals( vVel, flDist, flRadius )
|
|
local info =
|
|
{
|
|
Ability = self,
|
|
vSpawnOrigin = self:GetCaster():GetAbsOrigin(),
|
|
fStartRadius = flRadius,
|
|
fEndRadius = flRadius,
|
|
vVelocity = vVel,
|
|
fDistance = flDist,
|
|
Source = self:GetCaster(),
|
|
iUnitTargetTeam = DOTA_UNIT_TARGET_TEAM_ENEMY,
|
|
iUnitTargetType = DOTA_UNIT_TARGET_HERO + DOTA_UNIT_TARGET_BASIC,
|
|
fExpireTime = GameRules:GetGameTime() + 10.0,
|
|
}
|
|
|
|
return ProjectileManager:CreateLinearProjectile( info )
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:OnProjectileThinkHandle( iProjectileHandle )
|
|
if IsServer() then
|
|
local info = nil
|
|
for _,v in pairs ( self.Projectiles ) do
|
|
if v.nHandle == iProjectileHandle then
|
|
info = v
|
|
break
|
|
end
|
|
end
|
|
|
|
if info == nil then
|
|
return
|
|
end
|
|
|
|
if self.nPattern == PATTERN_SPIRAL then
|
|
self:ThinkSpiralProjectile( info )
|
|
end
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------
|
|
|
|
function aghanim_shard_attack:OnProjectileHitHandle( hTarget, vLocation, iProjectileHandle )
|
|
if IsServer() then
|
|
local info = nil
|
|
for _,v in pairs ( self.Projectiles ) do
|
|
if v.nHandle == iProjectileHandle then
|
|
info = v
|
|
break
|
|
end
|
|
end
|
|
|
|
if info == nil then
|
|
return false
|
|
end
|
|
|
|
if self.nPattern == PATTERN_SPIRAL then
|
|
ParticleManager:DestroyParticle( info.nFXIndex, false )
|
|
UTIL_Remove( info.attachEnt )
|
|
info.attachEnt = nil
|
|
end
|
|
|
|
if hTarget and not hTarget:IsMagicImmune() and not hTarget:IsInvulnerable() then
|
|
local damage =
|
|
{
|
|
victim = hTarget,
|
|
attacker = self:GetCaster(),
|
|
damage = self.spiral_projectile_damage,
|
|
damage_type = DAMAGE_TYPE_PURE,
|
|
ability = self,
|
|
}
|
|
|
|
ApplyDamage( damage )
|
|
|
|
EmitSoundOn( "Hero_Silencer.LastWord.Damage", hTarget )
|
|
|
|
local nFXIndex = ParticleManager:CreateParticle( "particles/units/heroes/hero_lich/lich_frost_nova.vpcf", PATTACH_WORLDORIGIN, nil )
|
|
ParticleManager:SetParticleControl( nFXIndex, 0, hTarget:GetAbsOrigin() )
|
|
ParticleManager:SetParticleControl( nFXIndex, 1, Vector( self.spiral_projectile_width, self.spiral_projectile_width, self.spiral_projectile_width ) )
|
|
ParticleManager:ReleaseParticleIndex( nFXIndex )
|
|
end
|
|
end
|
|
|
|
return true
|
|
end |