function OnMiko01SpellStart(keys)
	local caster = EntIndexToHScript(keys.caster_entindex)
	local forward = caster:GetForwardVector()

	local effectIndex = ParticleManager:CreateParticle("particles/thd2/heroes/miko/ability_miko_01.vpcf", PATTACH_CUSTOMORIGIN, caster)
	ParticleManager:SetParticleControl(effectIndex, 0, caster:GetOrigin()+Vector(0,0,64))
	ParticleManager:SetParticleControlForward(effectIndex , 0, caster:GetForwardVector())
	ParticleManager:DestroyParticleSystem(effectIndex,false)
	
	keys.ability:ApplyDataDrivenModifier(caster, caster, "modifier_miko_01_pose", {})

	local bonus = math.floor(keys.power_damage2 * caster:THTD_GetStarDamage())
	for i=1,3 do
		local rollRad = (i-2)*math.pi/4
		local currentPoint = Vector(math.cos(rollRad)*forward.x - math.sin(rollRad)*forward.y,
								 forward.y*math.cos(rollRad) + forward.x*math.sin(rollRad),
								 0) * keys.range + caster:GetOrigin()
		local targets = 
			FindUnitsInLine(
				caster:GetTeamNumber(), 
				caster:GetOrigin(), 
				currentPoint, 
				nil, 
				200,
				keys.ability:GetAbilityTargetTeam(), 
				keys.ability:GetAbilityTargetType(), 
				keys.ability:GetAbilityTargetFlags()
			)
		local damage = caster:THTD_GetAbilityPowerDamage(keys.ability, 1)
		for k,v in pairs(targets) do
			local DamageTable = {
	   			ability = keys.ability,
	            victim = v, 
	            attacker = caster, 
	            damage = damage, 
	            damage_type = keys.ability:GetAbilityDamageType(), 
	            damage_flags = DOTA_DAMAGE_FLAG_NONE
		   	}
			UnitDamageTarget(DamageTable)
			
			if THTD_IsValid(v) then
				v:AddDamageBlockAll(-bonus, "thtd_miko_01_bonus")
				local modifier = v:FindModifierByName("modifier_miko_01_debuff")
				if modifier == nil then 
					keys.ability:ApplyDataDrivenModifier(caster, v, "modifier_miko_01_debuff", {})
				else
					modifier:SetDuration(keys.duration_time, false)
				end
			end
		end
	end
	
end

function OnDestroyMiko01DeBuff(keys)
	keys.target:AddDamageBlockAll("thtd_miko_01_bonus")	
end

function OnMiko02SpellStart(keys)
	local caster = EntIndexToHScript(keys.caster_entindex)
	local target = keys.target

	if THTD_IsTempleOfGodCanBuffedTower(target) then
		if caster.thtd_miko_02_religious_count == nil then
			caster.thtd_miko_02_religious_count = 0
		end

		if caster.thtd_miko_02_religious_count >= 6000 and target:HasModifier("modifier_miko_02_buff") == false then
			local unitName = target:GetUnitName()
			if unitName == "soga" then
				target.thtd_miko_buff_soga01 = keys.soga01_cd
				target.thtd_miko_buff_soga03 = keys.soga03_cd
			elseif unitName == "futo" then
				target.thtd_miko_buff_futo03 = keys.futo03_up
			elseif unitName == "yoshika" then
				target.thtd_miko_buff_yoshika = keys.yoshika
			elseif unitName == "seiga" then
				target.thtd_miko_buff_seiga = keys.seiga
			end
			caster:RemoveModifierByName("modifier_miko_02_ready")			
			keys.ability:ApplyDataDrivenModifier(caster, target, "modifier_miko_02_buff", {})			
			caster.thtd_miko_02_religious_count = 0
		end
	end
end

function OnMiko02SpellThink(keys)
	if GameRules:IsGamePaused() then return end
	local caster = EntIndexToHScript(keys.caster_entindex)
	local targets = THTD_FindFriendlyUnitsInRadius(caster,caster:GetOrigin(),1500)

	for k,v in pairs(targets) do
		if THTD_IsTempleOfGodCanBuffedTower(v) then
			if caster.thtd_miko_02_religious_count == nil then
				caster.thtd_miko_02_religious_count = 0
			end
			if caster.thtd_miko_02_religious_count < 6000 then
				caster.thtd_miko_02_religious_count = caster.thtd_miko_02_religious_count + 1
				SendOverheadEventMessage(caster:GetPlayerOwner(), OVERHEAD_ALERT_BONUS_POISON_DAMAGE, caster, caster.thtd_miko_02_religious_count, caster:GetPlayerOwner() )
			elseif caster:HasModifier("modifier_miko_02_ready") == false then
				keys.ability:ApplyDataDrivenModifier(caster, caster, "modifier_miko_02_ready", {})
			end
		end
	end

	local count = 0
	local friends = THTD_FindFriendlyUnitsAll(caster)
	for k,v in pairs(friends) do 
		if THTD_IsTempleOfGodCanBuffedTower(v) then
			local modifier = v:FindModifierByName("modifier_miko_02_buff")
			if modifier ~= nil then 
				if modifier:GetCaster() == caster then 
					count = count + 1
				end
			end
		end
	end
	if count > 0 then 
		if count ~= caster.thtd_miko_03_count then
			caster:THTD_AddBasePower(keys.bonus_power * count, "thtd_miko_03_bonus")
			caster:THTD_AddBaseAttack(keys.bonus_power * count, "thtd_miko_03_bonus")
			caster:THTD_AddCritChance(keys.bonus_chance * count, "thtd_miko_03_bonus")
			caster:THTD_AddCritDamage(keys.bonus_crit * count, "thtd_miko_03_bonus")
			caster.thtd_miko_03_count = count
		end
	else
		caster:THTD_AddBasePower("thtd_miko_03_bonus")
		caster:THTD_AddBaseAttack("thtd_miko_03_bonus")
		caster:THTD_AddCritChance("thtd_miko_03_bonus")
		caster:THTD_AddCritDamage("thtd_miko_03_bonus")
		if count ~= caster.thtd_miko_03_count then
			caster.thtd_miko_03_count = count
		end
	end
end

function OnMiko03SpellHit(keys)
	local caster = EntIndexToHScript(keys.caster_entindex)
	local target = keys.target

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

function OnMiko03SpellThink(keys)
	if GameRules:IsGamePaused() then return end
	if keys.ability:GetLevel() < 1 then return end

	local caster = EntIndexToHScript(keys.caster_entindex)
   	local targets = THTD_FindUnitsInRadius(caster,caster:GetOrigin(),1200)

   	if #targets > 0 then
		local index = RandomInt(1,#targets)
		if IsValidAlive(targets[index]) then
			local info = 
			{
				Target = targets[index],
				Source = caster,
				Ability = keys.ability,	
				EffectName = "particles/heroes/thtd_miko/ability_miko_03.vpcf",
		        iMoveSpeed = 1400,
				vSourceLoc= caster:GetAbsOrigin(),                -- Optional (HOW)
				bDrawsOnMinimap = false,                          -- Optional
			    bDodgeable = true,                                -- Optional
			  	bIsAttack = false,                                -- Optional
			    bVisibleToEnemies = true,                         -- Optional
			    bReplaceExisting = false,                         -- Optional
			    flExpireTime = GameRules:GetGameTime() + 10,      -- Optional but recommended
				bProvidesVision = true,                           -- Optional
				iVisionRadius = 400,                              -- Optional
				iVisionTeamNumber = caster:GetTeamNumber()        -- Optional
			}
			local projectile = ProjectileManager:CreateTrackingProjectile(info)
			ParticleManager:DestroyLinearProjectileSystem(projectile,false)

			local friends = THTD_FindFriendlyUnitsAll(caster)
			for k,believer in pairs(friends) do
				if believer:HasModifier("modifier_miko_02_buff") then   					
					local index_extra = RandomInt(1,#targets)
					if IsValidAlive(targets[index_extra]) then
						local info_extra = 
						{
							Target = targets[index_extra],
							Source = caster,
							Ability = keys.ability,	
							EffectName = "particles/heroes/thtd_miko/ability_miko_03.vpcf",
							iMoveSpeed = 1400,
							vSourceLoc= caster:GetAbsOrigin(),                -- Optional (HOW)
							bDrawsOnMinimap = false,                          -- Optional
							bDodgeable = true,                                -- Optional
							bIsAttack = false,                                -- Optional
							bVisibleToEnemies = true,                         -- Optional
							bReplaceExisting = false,                         -- Optional
							flExpireTime = GameRules:GetGameTime() + 10,      -- Optional but recommended
							bProvidesVision = true,                           -- Optional
							iVisionRadius = 400,                              -- Optional
							iVisionTeamNumber = caster:GetTeamNumber()        -- Optional
						}
						local projectile_extra = ProjectileManager:CreateTrackingProjectile(info_extra)
						ParticleManager:DestroyLinearProjectileSystem(projectile_extra,false)
					end
				end
			end
		end
	end
end


function OnCreatedMiko04(keys)
	local caster = EntIndexToHScript(keys.caster_entindex)
	local forward = caster:GetForwardVector()
	local ability = caster:FindAbilityByName("thtd_miko_01")

	local power_damage2 = ability:GetSpecialValueFor("power_damage2")
	local range = ability:GetSpecialValueFor("range")
	local duration_time = math.floor(ability:GetSpecialValueFor("duration_time") * 100 + 0.5) / 100
	
	local effectIndex = ParticleManager:CreateParticle("particles/thd2/heroes/miko/ability_miko_01.vpcf", PATTACH_CUSTOMORIGIN, caster)
	ParticleManager:SetParticleControl(effectIndex, 0, caster:GetOrigin()+Vector(0,0,64))
	ParticleManager:SetParticleControlForward(effectIndex , 0, caster:GetForwardVector())
	ParticleManager:DestroyParticleSystem(effectIndex,false)

	local bonus = math.floor(power_damage2 * caster:THTD_GetStarDamage())
	for i=1,3 do
		local rollRad = (i-2)*math.pi/4
		local currentPoint = Vector(math.cos(rollRad)*forward.x - math.sin(rollRad)*forward.y,
								 forward.y*math.cos(rollRad) + forward.x*math.sin(rollRad),
								 0) * range + caster:GetOrigin()
		local targets = 
			FindUnitsInLine(
				caster:GetTeamNumber(), 
				caster:GetOrigin(), 
				currentPoint, 
				nil, 
				200,
				ability:GetAbilityTargetTeam(), 
				ability:GetAbilityTargetType(), 
				ability:GetAbilityTargetFlags()
			)
		local damage = caster:THTD_GetAbilityPowerDamage(ability, 1)
		for k,v in pairs(targets) do
			local DamageTable = {
	   			ability = ability,
	            victim = v, 
	            attacker = caster, 
	            damage = damage, 
	            damage_type = ability:GetAbilityDamageType(), 
	            damage_flags = DOTA_DAMAGE_FLAG_NONE
		   	}
			UnitDamageTarget(DamageTable)
			
			if THTD_IsValid(v) then
				v:AddDamageBlockAll(-bonus, "thtd_miko_01_bonus")
				local modifier = v:FindModifierByName("modifier_miko_01_debuff")
				if modifier == nil then 
					ability:ApplyDataDrivenModifier(caster, v, "modifier_miko_01_debuff", {})
				else
					modifier:SetDuration(duration_time, false)
				end
			end
		end
	end
end

function OnMiko04SpellThink(keys)
	if GameRules:IsGamePaused() then return end
	local caster = EntIndexToHScript(keys.caster_entindex)
	local inners = THTD_FindUnitsInner(caster)
	local friends = THTD_FindFriendlyUnitsAll(caster)

	local castUnits = {}
	for k,v in pairs(friends) do 
		if v == caster then 
			table.insert(castUnits, v)
		elseif v:HasModifier("modifier_miko_02_buff") then
			local modifier = v:FindModifierByName("modifier_miko_04_pose")
			if modifier == nil then 
				table.insert(castUnits, v)
			elseif modifier:GetCaster() == caster then 
				table.insert(castUnits, v)
			end
		end
	end

	local damage = caster:THTD_GetAbilityPowerDamage(keys.ability)	

	for index,believer in pairs(castUnits) do
		local modifier = believer:FindModifierByName("modifier_miko_04_pose")
		if modifier == nil then 
			-- tick+0.1
			keys.ability:ApplyDataDrivenModifier(caster, believer, "modifier_miko_04_pose", {Duration = 0.5})
		else
			modifier:SetDuration(0.5, false)
		end
		if believer ~= caster then
			modifier = believer:FindModifierByName("modifier_miko_04_pose_other")
			if modifier == nil then 
				-- tick+0.1
				keys.ability:ApplyDataDrivenModifier(caster, believer, "modifier_miko_04_pose_other", {Duration = 0.5})
			else
				modifier:SetDuration(0.5, false)
			end
		end

		for k,v in pairs(inners) do
			if RandomInt(1,3) == 1 then
				local effectIndex = ParticleManager:CreateParticle("particles/heroes/thtd_miko/ability_thtd_miko_04_starfall.vpcf",PATTACH_CUSTOMORIGIN,caster)
				ParticleManager:SetParticleControl(effectIndex, 0, v:GetOrigin())
				ParticleManager:SetParticleControl(effectIndex, 2, RandomVector(255))
				ParticleManager:SetParticleControl(effectIndex, 4, Vector(255,255,255))
				ParticleManager:DestroyParticleSystem(effectIndex,false)

				caster:SetContextThink(DoUniqueString("thtd_miko_04_star_fall"), 
					function()
						if GameRules:IsGamePaused() then return 0.03 end
						
						local deal_damage = damage
						local modifier = v:FindModifierByName("modifier_miko_04_debuff")
						if modifier == nil then 
							keys.ability:ApplyDataDrivenModifier(caster, v, "modifier_miko_04_debuff", {})
						else
							modifier:SetDuration(1.5, false)
							deal_damage = deal_damage * (1 + math.min(keys.max_damage_up/100, modifier:GetStackCount()*keys.damage_up/100))
							modifier:SetStackCount(math.min(999,modifier:GetStackCount()+1))
						end					

						local damage_table = {
								ability = keys.ability,
								victim = v,
								attacker = caster,
								damage = deal_damage,
								damage_type = keys.ability:GetAbilityDamageType(), 
								damage_flags = 0
						}
						UnitDamageTarget(damage_table)							
						return nil
					end, 
				0.5)
			end
		end
	end
end