function OnSpellStartShikieiki01(keys)	
	local caster = EntIndexToHScript(keys.caster_entindex)
	local targets = THTD_FindUnitsInRadius(caster,caster:GetAbsOrigin(),keys.range)

	if GameRules:GetGameTime() - (caster.thtd_shikieiki_01_sound or 0) > 12 then 
		caster.thtd_shikieiki_01_sound = GameRules:GetGameTime()
		caster:EmitSound("Hero_Chen.PenitenceCast")
		caster:EmitSound("Hero_Chen.PenitenceImpact")
	end

	local damage = caster:THTD_GetAbilityPowerDamage(keys.ability)	
	for k,v in pairs(targets) do
		local effectIndex = ParticleManager:CreateParticle("particles/heroes/shikieiki/ability_shikieiki_01_guilty.vpcf", PATTACH_CUSTOMORIGIN, caster)
		ParticleManager:SetParticleControlEnt(effectIndex , 0, v, 5, "follow_origin", Vector(0,0,0), true)
		ParticleManager:DestroyParticleSystem(effectIndex, false)

		local modifier = v:FindModifierByName(keys.modifier)
		if modifier == nil then 
			modifier = keys.ability:ApplyDataDrivenModifier(caster, v, keys.modifier, nil)
			modifier:SetStackCount(RandomInt(1, 3))	
			local effectIndex2 = ParticleManager:CreateParticle("particles/heroes/shikieiki/ability_shikieiki_01_guilty_b.vpcf", PATTACH_CUSTOMORIGIN, caster)
			ParticleManager:SetParticleControlEnt(effectIndex2 , 0, v, 5, "follow_origin", Vector(0,0,0), true)			
			ParticleManager:SetParticleControl(effectIndex2, 1, v:GetOrigin())
			ParticleManager:SetParticleControl(effectIndex2, 2, v:GetOrigin())
			ParticleManager:SetParticleControl(effectIndex2, 3, v:GetOrigin())
			v.thtd_shikieiki_01_count_effect = effectIndex2
		else
			local count = modifier:GetStackCount()
			if count < 10 then 
				modifier:SetStackCount(math.min(10, count + RandomInt(1, 3)))
			end	
		end
		if modifier ~= nil then 
			ParticleManager:SetParticleControl(v.thtd_shikieiki_01_count_effect, 1, Vector(0,modifier:GetStackCount(),0))
		end		

		local damage_table = {
			ability = keys.ability,
			victim = v,
			attacker = caster,
			damage = damage,
			damage_type = keys.ability:GetAbilityDamageType(), 
			damage_flags = DOTA_DAMAGE_FLAG_NONE
		}
		UnitDamageTarget(damage_table)
	end
end

function OnDestroyShikieiki01Debuff(keys)	
	local target = keys.target			
	ParticleManager:DestroyParticleSystem(target.thtd_shikieiki_01_count_effect, true)
end

function OnSpellStartShikieiki02(keys)	
	local caster = EntIndexToHScript(keys.caster_entindex)
	local targets = THTD_FindUnitsInRadius(caster,caster:GetAbsOrigin(),keys.range)

	local count = 0
	local damage = caster:THTD_GetAbilityPowerDamage(keys.ability)
	for k,v in pairs(targets) do
		local effectIndex = ParticleManager:CreateParticle("particles/units/heroes/hero_omniknight/omniknight_purification.vpcf", PATTACH_CUSTOMORIGIN, caster)
		ParticleManager:SetParticleControl(effectIndex, 0, v:GetOrigin())
		ParticleManager:SetParticleControl(effectIndex, 1, Vector(1,1,1))
		ParticleManager:SetParticleControl(effectIndex, 2, Vector(0,0,0))
		ParticleManager:DestroyParticleSystem(effectIndex, false)
		
		local modifier = v:FindModifierByName(keys.modifier)
		local crit = 1
		if modifier ~= nil then 
			count = count + modifier:GetStackCount()
			crit = 1 + modifier:GetStackCount() * keys.damage_up/100
			modifier:Destroy()
		end	

		local damage_table = {
			ability = keys.ability,
			victim = v,
			attacker = caster,
			damage = damage * crit,
			damage_type = keys.ability:GetAbilityDamageType(), 
			damage_flags = DOTA_DAMAGE_FLAG_NONE
		}
		UnitDamageTarget(damage_table)		
	end	
	
	if count > 0 then 
		caster.thtd_shikieiki_02_power_bonus = count * keys.power_bonus
		caster:RemoveModifierByName("modifier_shikieiki_02_buff")
		keys.ability:ApplyDataDrivenModifier(caster, caster, "modifier_shikieiki_02_buff", {})
	end
end

function OnCreatedShikieiki02Buff(keys)
	keys.target:THTD_AddBasePower(keys.target.thtd_shikieiki_02_power_bonus, "thtd_shikieiki_02_buff")
end

function OnDestroyShikieiki02Buff(keys)
	keys.target:THTD_AddBasePower("thtd_shikieiki_02_buff")
end

function OnCreatedShikieiki03Debuff(keys)
	local caster = keys.caster
	local target = keys.target
	local effectIndex = ParticleManager:CreateParticle(
		"particles/heroes/shikieiki/ability_shikieiki_04.vpcf", 
		PATTACH_CUSTOMORIGIN, 
		target)
	ParticleManager:SetParticleControlEnt(effectIndex , 0, target, 5, "follow_origin", Vector(0,0,0), true)
	ParticleManager:SetParticleControlEnt(effectIndex , 1, target, 5, "follow_origin", Vector(0,0,0), true)
	ParticleManager:SetParticleControlEnt(effectIndex , 4, target, 5, "follow_origin", Vector(0,0,0), true)
	target.thtd_shikieiki_03_effect = effectIndex

	if not keys.ability:GetAutoCastState() then 
		caster:EmitSound("Voice_Thdots_Shikieiki.AbilityShikieiki04")
	end
end

function OnIntervalThinkShikieiki03(keys)
	UnitDamageHpRemove(keys.caster, keys.target, keys.hp_damage, false)
end

function OnDestroyShikieiki03Debuff(keys)
	ParticleManager:DestroyParticleSystem(keys.target.thtd_shikieiki_03_effect, true)
end

function OnSpellStartShikieiki04(keys)
	local caster = EntIndexToHScript(keys.caster_entindex)
	local targetPoint = keys.target_points[1]

	local effectIndex = ParticleManager:CreateParticle("particles/econ/items/enigma/enigma_world_chasm/enigma_blackhole_ti5.vpcf", PATTACH_CUSTOMORIGIN, caster)
	ParticleManager:SetParticleControl(effectIndex, 0, targetPoint)

	caster:EmitSound("Hero_Enigma.Black_Hole")	

	local time = keys.duration_time
	local tick = 0.05
	local count = 0
	local damage_tick = math.floor(keys.tick * 100 + 0.5)/100
	local damage_count = math.floor(damage_tick/tick)
	caster:SetContextThink(DoUniqueString("thtd_shikieiki_04"), 
		function()
			if GameRules:IsGamePaused() then return 0.1 end
			count = count + 1
			if time < 0 or THTD_IsValid(caster) == false then 
				ParticleManager:DestroyParticleSystem(effectIndex, true)
				caster:StopSound("Hero_Enigma.Black_Hole")
				return nil 
			end

			local targets = THTD_FindUnitsInRadius(caster,targetPoint,keys.radius)
			local damage = 0
			if count%damage_count == 0 then 
				damage = caster:THTD_GetAbilityPowerDamage(keys.ability)				
			end

			for k, v in pairs(targets) do
				local distance = (v:GetAbsOrigin() - targetPoint):Length2D()
				local in_pull = 400
				local new_pos = GetGroundPosition(RotatePosition(targetPoint, QAngle(0,1.5,0), v:GetAbsOrigin()), v)
				if distance > 20 then
					local direction = (targetPoint - new_pos):Normalized()
					direction.z = 0.0
					new_pos = new_pos + direction * in_pull * tick
				end
				v:SetOrigin(new_pos)				

				if damage > 0 then 
					local damage_table = {
						ability = keys.ability,
						victim = v,
						attacker = caster,
						damage = damage,
						damage_type = keys.ability:GetAbilityDamageType(), 
						damage_flags = DOTA_DAMAGE_FLAG_NONE
					}
					UnitDamageTarget(damage_table)
				end
			end
			time = time - tick
			return tick
		end,
	0)
end


