THTD_MAX_BONUS_TOWER = 3

local thtd_skin_list = 
{
	["suwako"] = 
	{
		[1] = "models/thd_hero/suwako/cloth01/suwako_cloth01.vmdl",
	},	
	["meirin"] = 
	{
		[1] = "models/thd_hero/meirin/cloth01/meirin_cloth01.vmdl",
	},	
	["sanae"] = 
	{
		[1] = "models/thd_hero/sanae/cloth01/sanae_jk.vmdl",
	},
	["mystia"] = 
	{
		[1] = "models/thd_hero/mystia/cloth01/mystia_cloth01.vmdl",
	},	
}

function OnTouhouReleaseTowerSpellStart(keys)
	local caster = keys.caster
	local target = keys.target

	if caster:GetNumItemsInInventory() >= THTD_MAX_ITEM_SLOT then 
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="not_enough_item_slot"})
		EmitSoundOn("Sound_THTD.thtd_star_up_fail", caster)
		return 
	end

	if target:THTD_IsTower() and target:GetOwner() == caster then	
		local item = target.thtd_item
		if item == nil then return end
		
		if item.locked_by_player_id == nil then 
			target:THTD_DropItemAll()
		end
		target:AddNewModifier(caster, nil, "modifier_touhoutd_release_hidden", {})
		target:SetAbsOrigin(Vector(0,0,0))
		target:AddNoDraw()
		target:THTD_DestroyLevelEffect()
		target:RemoveModifierByName("modifier_hidden_bar")
		target:THTD_ResetTowerDamage()	
		
		item:THTD_UpdateItemStarLevel()
		caster:AddItem(item)

		for k,v in pairs(caster.thtd_hero_tower_list) do
			if v == target then
				table.remove(caster.thtd_hero_tower_list,k)
				break
			end
		end

		for k,v in pairs(caster.thtd_hero_tower_list) do
			if v==nil or v:IsNull() or v:IsAlive()==false or v:THTD_IsHidden() then
				table.remove(caster.thtd_hero_tower_list,k)				
			end
		end

		caster.thtd_game_info["food_count"] = #caster.thtd_hero_tower_list
		SetNetTableTowerList(caster)

		-- 取消相关buff
		for k,v in pairs(caster.thtd_hero_tower_list) do
			if v ~= target then
				local modifiers = v:FindAllModifiers()
				for _, modifier in pairs(modifiers) do
					if modifier:GetCaster() == target and THTD_IsRemainBuff(modifier:GetName()) == false then modifier:Destroy() end
				end
			end			
		end		

		local entities = Entities:FindAllByClassname("npc_dota_creature")						
		for k,v in pairs(entities) do
			if v~=nil and v:IsNull()==false and v:IsAlive() and v.thtd_spawn_unit_owner~=nil and v.thtd_spawn_unit_owner==target then 
				v:AddNoDraw()
				v:ForceKill(false)
			end
		end

		local unitName = target:GetUnitName()

		-- 取消来源本单位的buff
		if unitName == "hatate" then
			local inners = THTD_FindUnitsInner(target)
			local outers = THTD_FindUnitsOuter(target)	
			for k,v in pairs(inners) do
				if THTD_IsValid(v) and v:HasModifier("modifier_hatate01_news_buff") then					
					if v:FindModifierByName("modifier_hatate01_news_buff"):GetCaster() == target then 
						v:RemoveModifierByName("modifier_hatate01_news_buff")
					end
				end
			end
			for k,v in pairs(outers) do
				if THTD_IsValid(v) and v:HasModifier("modifier_hatate01_news_buff") then
					if v:FindModifierByName("modifier_hatate01_news_buff"):GetCaster() == target then 
						v:RemoveModifierByName("modifier_hatate01_news_buff")
					end
				end
			end
		end

		-- 取消辉夜buff
		for i=1,4 do
			local buff = "modifier_kaguya_03_"..i.."_buff"			
			if target:HasModifier(buff) then
				target:RemoveModifierByName(buff)
			end
		end

		caster:THTD_HeroComboRefresh()
	end
end

function PutTowerToPoint(keys)
	local caster = keys.caster
	if caster:IsRealHero() == false then return end
	local targetPoint = keys.target_points[1]
	local itemName = keys.ability:GetAbilityName()
	local tower = keys.ability.tower
	local playerid = caster:GetPlayerOwnerID()

	if caster.thtd_game_info["food_count"] ~= #caster.thtd_hero_tower_list then
		caster.thtd_game_info["food_count"] = #caster.thtd_hero_tower_list
		SetNetTableTowerList(caster)
	end
	if caster.thtd_game_info["food_count"] >= GameRules.GameData.max_food then 
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner() , "display_custom_error", {msg="not_enough_food"} )
		return 
	end

	if IsMaxCountCheckOK(caster, itemName) == false then
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner() , "display_custom_error", {msg="the_same_card_reach_to_limit"} )
		return 
	end

	if SpawnSystem.IsUnLimited == false and IsBonusTower(itemName) and GetBonusTowerCount(caster) >= THTD_MAX_BONUS_TOWER then
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner() , "show_message", {msg="bonus_tower_limit", duration=5, params={count=1}, color="#0ff"} )
		return 
	end
	
	if GameRules.GameData.new_card_list ~= "" and string.find(","..GameRules.GameData.new_card_list..",",","..keys.ability:THTD_GetCardName()..",") ~= nil and GameRules.PlayerData[caster:GetPlayerOwnerID()].vip == 0 and tostring(PlayerResource:GetSteamID(caster:GetPlayerOwnerID())) ~= GameRules.GameData.admin then 
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="new_card_test_tip"})	
		return 
	end

	if GameRules:GetCustomGameDifficulty() >= FUNNY_MODE and SpawnSystem.IsUnLimited == false and IsBonusTower(itemName) then 
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="funny_mode_bonus_no_use_tip"})	
	end	

	if tower == nil then
		local spawnTowerName = towerNameList[itemName]["cardname"]
		tower = CreateUnitByName(
			spawnTowerName, 
			targetPoint, 
			false, 
			caster, 
			caster, 
			caster:GetTeam() 
		)

		if (GameRules.GameData.is_open_day == 1 or GameRules.PlayerData[playerid].vip == 1 or tostring(PlayerResource:GetSteamID(playerid)) == GameRules.GameData.admin) and thtd_skin_list[spawnTowerName] ~= nil then
			local skin_index = RandomInt(1, #thtd_skin_list[spawnTowerName])
			local model_name = thtd_skin_list[spawnTowerName][skin_index]

			tower:SetModel(model_name)
			tower:SetOriginalModel(model_name)
		end

		tower:SetControllableByPlayer(playerid, true) 
		tower:SetOwner(caster)
		tower:SetHullRadius(50)
		FindClearSpaceForUnit(tower, targetPoint, false)

		tower:SetForwardVector(Vector(0,-1,tower:GetForwardVector().z))
		keys.ability.tower = tower
	else
		if tower:GetOwner() ~= caster then
			tower:SetOwner(caster)
			tower:SetControllableByPlayer(playerid, true) 
		end
		tower:SetAbsOrigin(targetPoint)
		tower:SetContextThink(DoUniqueString("FindClearSpaceForUnit"), 
			function()
				if GetDistanceBetweenTwoVec2D(tower:GetOrigin(),targetPoint) < 100 then
					tower:RemoveModifierByName("modifier_touhoutd_release_hidden")
					tower:RemoveNoDraw()
					FindClearSpaceForUnit(tower, targetPoint, false)
					tower:THTD_DestroyLevelEffect()
					tower:THTD_CreateLevelEffect()					
					return nil
				end
				return 0.1
			end,
		0)
		tower:SetForwardVector((Vector(0,0,128)-caster:GetAbsOrigin()):Normalized())
	end

	tower:SetHealth(1)

	if keys.ability:THTD_IsCardHasVoice() == true then
		EmitSoundOn(THTD_GetVoiceEvent(towerNameList[itemName]["cardname"],"spawn"),tower)
	end

	tower.thtd_item = keys.ability
	caster:TakeItem(keys.ability)
	tower:SetMana(0)
	caster:EmitSound("Sound_THTD.thtd_set_tower")

	table.insert(caster.thtd_hero_tower_list,tower)
	caster.thtd_game_info["food_count"] = #caster.thtd_hero_tower_list	
	SetNetTableTowerList(caster)	

	tower:AddNewModifier(caster, nil, "modifier_touhoutd_building", {})
	tower:SetContextThink(DoUniqueString("thtd_modifier_touhoutd_building"), 
		function()
			if GameRules:IsGamePaused() then return 0.03 end
			if tower:GetHealth() >= tower:GetMaxHealth() then 
				tower:AddNewModifier(tower, nil, "modifier_hidden_bar", {})				
				tower:RemoveModifierByName("modifier_touhoutd_building")
							
				caster:THTD_HeroComboRefresh()					
				tower:SetLuckDay()
				tower:EnableAi()	
				return nil 
			end
			tower:SetHealth(tower:GetHealth()+4)
			return 0.04
		end, 
	0)

	if tower.isFirstSpawn ~= true then 
		tower.isFirstSpawn = true
		tower:THTD_InitExp()
		tower:AddNewModifier(caster, nil, "modifier_touhoutd_root", {})
	else
		tower:THTD_DestroyLevelEffect()
		tower:THTD_CreateLevelEffect()
	end	

	local modifiers = tower:FindAllModifiers()
	for _, modifier in pairs(modifiers) do
		if THTD_IsRemainBuff(modifier:GetName()) == false and modifier:GetCaster() ~= tower and THTD_IsValid(modifier:GetCaster()) == false then 			
			modifier:Destroy() 
		end
	end	

	local powerLevelFromItem = tower.thtd_power_from_item or 0
	local powerLevelFromCard = 0	
	if GameRules.PlayerData[playerid]["level_list"] ~= nil then
		powerLevelFromCard = GameRules.PlayerData[playerid]["level_list"][itemName] or 0
	end
	local count = math.min(999, powerLevelFromItem + powerLevelFromCard)
	local modifier = tower:FindModifierByName("modifier_fairy_count")
	if modifier == nil then
		if count > 0 then 
			tower:AddNewModifier(tower, nil, "modifier_fairy_count", nil):SetStackCount(count)
		end
	elseif count ~= modifier:GetStackCount() then
		if count > 0 then 
			modifier:SetStackCount(count)
		else
			tower.thtd_power_level = nil 
			target:RemovePowerBonus()
			tower:RemoveAbility("e316")
			tower:RemoveModifierByName('modifier_texiao_star')
		end		
	end
	
	if tower:HasModifier("modifier_fairy_count") then
		if towerNameList[itemName]["quality"] == 1 then 
			tower.thtd_power_level = tower:FindModifierByName("modifier_fairy_count"):GetStackCount()		
			tower:AddPowerBonus()	
			AddAbilityAndSetLevel(tower, "e316")
			tower:EmitSound("Sound_THTD.thtd_star_up")	
		end		
	end
end


THTD_STAR_ITEM = 
{
	[1] = "item_1003",
	[2] = "item_1004",
	[3] = "item_1005",
	[4] = "item_1006",
}

THTD_SEIGA_STAR_ITEM = 
{
	[1] = "item_1011",
	[2] = "item_1012",
	[3] = "item_1013",
	[4] = "item_1014",
}

function StarUp(keys)
	local caster = keys.caster
	local player = caster:GetPlayerOwner()
	local hero = player:GetAssignedHero()
	local star = caster:THTD_GetStar()

	-- print("-----------this tower buffs:")
	-- local modifiers = caster:FindAllModifiers()
	-- for _, modifier in pairs(modifiers) do
	-- 	print(modifier:GetName())
	-- end
	-- print("-----------enemy buffs:")
	-- local buffs = {}
	-- local targets = THTD_FindUnitsAll(caster)
	-- for k, v in pairs(targets) do
	-- 	local modifiers = v:FindAllModifiers()
	-- 	for _, modifier in pairs(modifiers) do
	-- 		local name = modifier:GetName()
	-- 		local isExist = false
	-- 		for _, b in pairs(buffs) do
	-- 			if b == name then 
	-- 				isExist = true 
	-- 				break
	-- 			end
	-- 		end
	-- 		if not isExist then 
	-- 			table.insert(buffs, name) 
	-- 			print(name)
	-- 		end
	-- 	end
	-- end

	-- local ens = Entities:FindAllInSphere(caster:GetAbsOrigin(), 3000)
	-- for k,v in pairs(ens) do
	-- 	print("---------------")
	-- 	print(v:GetClassname())		
	-- 	if v:GetClassname() == "dota_death_prophet_exorcism_spirit" then 
	-- 		-- print(v:GetUnitName())	
	-- 		local f = v:GetOwner()
	-- 		if f ~= nil then print(f:GetUnitName()) end
	-- 		-- v:Kill()
	-- 		-- UTIL_Remove(v)
	-- 	end
	-- end



	if caster:THTD_GetLevel() < THTD_MAX_LEVEL or star >= 5 then 
		if player then
			EmitSoundOn("Sound_THTD.thtd_star_up_fail",caster)
		end
		return 
	end

	composeItem = {}
	
	for item_slot = 0,5 do
		local item = caster:GetItemInSlot(item_slot)		
		if item ~= nil and item.locked_by_player_id == nil then
			local tower = item:THTD_GetTower()
			if tower ~= nil and tower:THTD_GetStar() == star and tower:THTD_GetLevel() == THTD_MAX_LEVEL then	
				if GameRules:GetCustomGameDifficulty() >= FUNNY_MODE and tower:GetUnitName() == "minoriko" then 				
					CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="minoriko_cannot_be_material"})		
				else
					table.insert(composeItem,item)
				end							
			end
			if item:GetAbilityName() == THTD_STAR_ITEM[star] or item:GetAbilityName() == THTD_SEIGA_STAR_ITEM[star] then
				table.insert(composeItem,item)
			end
		end
	end

	for item_slot = 0,5 do
		local item = hero:GetItemInSlot(item_slot)				
		if item ~= nil and item.locked_by_player_id == nil then
			local tower = item:THTD_GetTower()
			if tower ~= nil and tower:THTD_GetStar() == star and tower:THTD_GetLevel() == THTD_MAX_LEVEL then					
				if GameRules:GetCustomGameDifficulty() >= FUNNY_MODE and tower:GetUnitName() == "minoriko" then 
					CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="minoriko_cannot_be_material"})		
				else
					table.insert(composeItem,item)
				end			
			end
			if item:GetAbilityName() == THTD_STAR_ITEM[star] or item:GetAbilityName() == THTD_SEIGA_STAR_ITEM[star] then
				table.insert(composeItem,item)
			end
		end
	end

	if (#composeItem >= star) then
		for i=1,star do			
			OnItemDestroyed(caster, composeItem[i], false)
		end
		caster:THTD_StarUp()		
	else		
		EmitSoundOn("Sound_THTD.thtd_star_up_fail",caster)	
	end
	composeItem = {}
end

function ExpUp(keys)
	local caster = keys.caster
	local player = caster:GetPlayerOwner()
	local hero = player:GetAssignedHero()

	item = caster:GetItemInSlot(0)	

	if item ~= nil then		
		if item:THTD_GetCardName() == nil or string.find(item:THTD_GetCardName(),"item_20") ~= nil then		
			EmitSoundOn("Sound_THTD.thtd_star_up_fail",caster)			
			return
		end
			
		if item.locked_by_player_id ~= nil then		
			EmitSoundOn("Sound_THTD.thtd_star_up_fail",caster)
			if player then
				CustomGameEventManager:Send_ServerToPlayer(player , "display_custom_error", {msg="item_is_locked"} )				
			end
			return		
		end	
		
		caster:EmitSound("Sound_THTD.thtd_exp_up")		
		local tower = item:THTD_GetTower()
		local exp = 3000
		if tower ~= nil then
			if tower:GetUnitName() == "minoriko" and GameRules:GetCustomGameDifficulty() >= FUNNY_MODE then 
				CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="minoriko_cannot_be_material"})
				EmitSoundOn("Sound_THTD.thtd_star_up_fail",caster)
				return	
			end
			exp = (1000 + tower:THTD_GetExp()/5)*1500*(item:THTD_GetCardQuality()+1)/1000
		end
		if item:THTD_GetCardName() == caster:GetUnitName() then
			caster:THTD_SetAbilityLevelUp()
		elseif item:THTD_GetCardName() == "BonusEgg" then
			exp = (1000 + 5400/5)*1500*(item:THTD_GetCardQuality()+1)/1000		
		end
		caster:THTD_AddExp(exp)		
		OnItemDestroyed(caster, item, false)
	else
		EmitSoundOn("Sound_THTD.thtd_star_up_fail",caster)
	end
end

function BlinkToPoint(keys)
	local caster = keys.caster
	local targetPoint = keys.target_points[1]

	-- 向量a点,b点，用b-a是a朝向b
	-- local forward = (targetPoint - caster:GetAbsOrigin()):Normalized()
	-- FindClearSpaceForUnit(caster, caster:GetAbsOrigin() + forward * 200, false)

	FindClearSpaceForUnit(caster, targetPoint, false)
	caster:EmitSound("Sound_THTD.ability_touhoutd_blink.End")

	if RollPercentage(50) then
		if caster:HasModifier("modifier_rainbow_tail") then 
			caster:RemoveModifierByName("modifier_rainbow_tail")
		else
			caster:AddNewModifier(caster, nil, "modifier_rainbow_tail", nil)
		end	
	end
end

function OnKillUnitSpellStart(keys)
	local caster = EntIndexToHScript(keys.caster_entindex)
	local target = keys.target	
	-- PrintTable(keys.ability:GetAbilityKeyValues())
	caster:EmitSound("Sound_THTD.ability_touhoutd_kill")	
	local effectIndex = ParticleManager:CreateParticle("particles/econ/items/lina/lina_ti6/lina_ti6_laguna_blade.vpcf", PATTACH_CUSTOMORIGIN, caster)
	ParticleManager:SetParticleControl(effectIndex, 0, caster:GetOrigin()+Vector(0,0,128))
	ParticleManager:SetParticleControl(effectIndex, 1, target:GetOrigin())
	ParticleManager:DestroyParticleSystem(effectIndex,false)
	
	if target.is_random_boss == nil or target:GetHealthPercent() <= 50 then 
		caster:NpcKill(target)
	else		
		target:SetHealth(math.max(10, target:GetHealth() - target:GetMaxHealth() * 0.5))
	end
end

function CloseStar(keys)
	local caster = keys.caster

	if caster.thtd_close_star ~= true then
		caster.thtd_close_star = true
	else
		caster.thtd_close_star = false
	end

	for index,tower in pairs(caster.thtd_hero_tower_list) do
		if tower ~= nil and tower:IsNull() == false then
			if caster.thtd_close_star == true and tower.thtd_is_effect_open == true and caster.focusTarget ~= tower then
				tower:THTD_DestroyLevelEffect()
			elseif caster.thtd_close_star == false and tower.thtd_is_effect_open == false then
				tower:THTD_CreateLevelEffect()
			end			
		end
	end
end

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

	if not target:THTD_IsTower() then 
		return 
	end

	if target:GetUnitName() == "rumia" and target:THTD_GetStar() == 5 and target:GetOwner() == caster and caster.thtd_ability_rumia_ex_lock ~= true then		
		target:EmitSound("Hero_Wisp.Tether")
		caster.thtd_ability_rumia_ex_lock = true
		target:THTD_UpgradeEx()	
		target:SetAttackCapability(DOTA_UNIT_CAP_MELEE_ATTACK)
		target:SetModel("models/thd2/rumia_ex/rumia_ex.vmdl")
		target:SetOriginalModel("models/thd2/rumia_ex/rumia_ex.vmdl")
		target:SetModelScale(0.7)
		local modifier = target:AddNewModifier(target, nil, "modifier_attack_time", {})
		modifier:SetStackCount(6)

		local attack_power_ability=target:FindAbilityByName("ability_common_power_buff")
		if attack_power_ability ~= nil then
			if attack_power_ability:GetLevel() < attack_power_ability:GetMaxLevel() then
				attack_power_ability:SetLevel(5)
			end
		end

		return
	end

	if caster:GetPlayerOwnerID() ~= target:GetPlayerOwnerID() then 
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="target_is_error"})	
		return 
	end

	if tostring(PlayerResource:GetSteamID(caster:GetPlayerOwnerID())) == GameRules.GameData.admin then
		if target.thtd_power_level == nil then
			if caster.is_team_mode ~= true then 
				local unitName = target:GetUnitName()
				if unitName ~= "minoriko" and unitName ~= "sizuha" and unitName ~= "lily" and unitName ~= "nazrin" then 
					caster.is_team_mode = true 	
					CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_chat_msg", {msg="team_rank_tip", params={player_name=PlayerResource:GetPlayerName(caster:GetPlayerOwnerID()),reason="潜能已激活"}})					
				end
			end	
			target.thtd_power_level = 10
			local modifier = target:FindModifierByName("modifier_fairy_count") or target:AddNewModifier(target, nil, "modifier_fairy_count", nil)			
			modifier:SetStackCount(10)
			AddAbilityAndSetLevel(target, "e316")
			target:EmitSound("Sound_THTD.thtd_star_up")							
		elseif target.thtd_power_level == 10 then
			target.thtd_power_level = 50
			target:FindModifierByName("modifier_fairy_count"):SetStackCount(50)
			target:EmitSound("Sound_THTD.thtd_star_up")
		elseif target.thtd_power_level == 50 then
			target.thtd_power_level = 100
			target:FindModifierByName("modifier_fairy_count"):SetStackCount(100)
			target:EmitSound("Sound_THTD.thtd_star_up")
		elseif target.thtd_power_level == 100 then
			target.thtd_power_level = 666
			target:FindModifierByName("modifier_fairy_count"):SetStackCount(666)
			target:EmitSound("Sound_THTD.thtd_star_up")
		elseif target.thtd_power_level == 666 then
			target.thtd_power_level = 999
			target:FindModifierByName("modifier_fairy_count"):SetStackCount(999)
			target:EmitSound("Sound_THTD.thtd_star_up")
		elseif target.thtd_power_level == 999 then
			target.thtd_power_level = nil
			target:RemoveModifierByName("modifier_fairy_count")
			target:RemovePowerBonus()
			target:RemoveAbility("e316")
			target:RemoveModifierByName('modifier_texiao_star')
			target:EmitSound("Sound_THTD.thtd_star_up_fail")			
		end
		target:AddPowerBonus()
	else
		if target.thtd_power_level == nil and target:HasModifier("modifier_fairy_count") then
			if caster.is_team_mode ~= true then 
				local unitName = target:GetUnitName()
				if unitName ~= "minoriko" and unitName ~= "sizuha" and unitName ~= "lily" and unitName ~= "nazrin" then 
					caster.is_team_mode = true 
					CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_chat_msg", {msg="team_rank_tip", params={player_name=PlayerResource:GetPlayerName(caster:GetPlayerOwnerID()),reason="潜能已激活"}})	
				end
			end
			target.thtd_power_level = target:FindModifierByName("modifier_fairy_count"):GetStackCount()		
			target:AddPowerBonus()	
			AddAbilityAndSetLevel(target, "e316")
			target:EmitSound("Sound_THTD.thtd_star_up")				
		end
	end
end

function OnIntervalThinkHeroEffect(keys)
	local caster = EntIndexToHScript(keys.caster_entindex)
	if caster:GetUnitName() ~= "npc_dota_hero_juggernaut" then return end
	local effectFile = {
		-- "particles/econ/items/juggernaut/jugg_arcana/juggernaut_arcana_v2_idle_rare.vpcf",
		"particles/econ/items/juggernaut/jugg_arcana/juggernaut_arcana_loadout_rare_model.vpcf"
	}
	local attachment = {
		"attach_hitloc",
		-- "blade_attachment",
		-- "attach_sword"
	}
	
	if caster.display_effect ~= nil then
		ParticleManager:DestroyParticleSystem(caster.display_effect, true)
	end

	local effectRandom = RandomInt(1, #effectFile)
	local effectAttach = attachment[RandomInt(1, #attachment)]
	-- print(effectRandom)
	-- print(effectAttach)
	local effectIndex = ParticleManager:CreateParticle(effectFile[effectRandom], PATTACH_CUSTOMORIGIN, caster)
	ParticleManager:SetParticleControlEnt(effectIndex , 0, caster, 5, effectAttach, Vector(0,0,0), true)	
	caster.display_effect = effectIndex
	-- if effectRandom == 1 then 
	-- 	ParticleManager:SetParticleControlEnt(effectIndex , 1, caster, 5, effectAttach, Vector(-70,-110,0), true)	
	-- 	ParticleManager:SetParticleControlEnt(effectIndex , 3, caster, 5, effectAttach, Vector(0,0,0), true)	
	-- else
	-- 	ParticleManager:SetParticleControlEnt(effectIndex , 3, caster, 5, effectAttach, Vector(0,0,0), true)	
	-- end	
end

function DrawNormalCard(keys)
	local caster = keys.caster
	local playerid = caster:GetPlayerOwnerID()

	if caster:GetNumItemsInInventory() >= THTD_MAX_ITEM_SLOT or caster:IsRealHero() == false then 
		if keys.ability:IsItem()==false then
			PlayerResource:ModifyGold(caster:GetPlayerOwnerID(), keys.ability:GetGoldCost(keys.ability:GetLevel()-1) , true, DOTA_ModifyGold_SellItem) 
		end
		local player = caster:GetPlayerOwner()
		EmitSoundOn("Sound_THTD.thtd_star_up_fail",caster)
		if player then			
			if caster:GetNumItemsInInventory() >= THTD_MAX_ITEM_SLOT then 
				CustomGameEventManager:Send_ServerToPlayer(player, "display_custom_error", {msg="not_enough_item_slot"})
			end
		end
		return 
	end	
	
	local drawList = {}	
	drawList[1] = {}
	drawList[2] = {}
	
	for k,v in pairs(towerPlayerList[caster.thtd_player_id+1]) do
		if v["quality"] == 1 and v["itemName"] ~= "BonusEgg" then
			for i=1,v["count"] do
				table.insert(drawList[1],v["itemName"])
			end
		elseif v["quality"] == 2 and v["itemName"] ~= "BonusEgg" then
			for i=1,v["count"] do
				table.insert(drawList[2],v["itemName"])
			end
		end
	end

	local rChance = 20
	local chance = RandomInt(1,100)
	local itemName = nil
	if chance <= rChance then
		if #drawList[2] > 0 then
			itemName = drawList[2][RandomInt(1,#drawList[2])]
		else
			THTD_ModifyGoldEx(caster:GetPlayerOwnerID(), 1000 , true, DOTA_ModifyGold_SellItem) 
		end
	else
		if #drawList[1] > 0 then
			itemName = drawList[1][RandomInt(1,#drawList[1])]
		else
			THTD_ModifyGoldEx(caster:GetPlayerOwnerID(), 250 , true, DOTA_ModifyGold_SellItem) 
		end
	end	
	if caster:THTD_AddCardPoolItem(itemName) == false then 
		if keys.ability:IsItem()==false then
			PlayerResource:ModifyGold(caster:GetPlayerOwnerID(), keys.ability:GetGoldCost(keys.ability:GetLevel()-1) , true, DOTA_ModifyGold_SellItem) 
		end
		return
	end

	if GameRules.player_bb_buff[playerid]["item_3012"] > 0 and RollPercentage(GameRules.player_bb_buff[playerid]["item_3012"]) then
		local quality = towerNameList[itemName]["quality"]
		local itemBonus = nil
		if quality == 2 then 
			itemBonus = CreateItem("item_2004", nil, nil)
		elseif quality == 3 then 
			itemBonus = CreateItem("item_2003", nil, nil)
		elseif quality == 4 then 
			itemBonus = CreateItem("item_2002", nil, nil)
		end
		if itemBonus ~= nil then	
			itemBonus.owner_player_id = playerid
			itemBonus:SetPurchaser(caster)
			itemBonus:SetPurchaseTime(1.0)
			
			if caster:GetNumItemsInInventory() >= THTD_MAX_ITEM_SLOT then 
				CreateItemOnPositionSync(caster:GetAbsOrigin(), itemBonus)
			else
				caster:AddItem(itemBonus)
			end		
		end	
	end

	if keys.ability:IsItem() then
		local charge = keys.ability:GetCurrentCharges()
		if charge > 1 then
			keys.ability:SetCurrentCharges(charge-1)
		else
			caster:RemoveItem(keys.ability)
		end
	else		
		if GameRules.player_bb_buff[playerid]["item_3018"] < 1 then 
			PlayerResource:ModifyGold(playerid, math.floor((keys.ability:GetGoldCost(keys.ability:GetLevel()-1)) * (1 - GameRules.player_bb_buff[playerid]["item_3018"])) , true, DOTA_ModifyGold_SellItem) 
		end
	end

	drawList = {}
end

function DrawSeniorCard(keys)
	local caster = keys.caster
	local playerid = caster:GetPlayerOwnerID()

	if caster:GetNumItemsInInventory() >= THTD_MAX_ITEM_SLOT or caster:IsRealHero() == false then 
		if keys.ability:IsItem()==false then
			PlayerResource:ModifyGold(caster:GetPlayerOwnerID(), keys.ability:GetGoldCost(keys.ability:GetLevel()-1) , true, DOTA_ModifyGold_SellItem) 
		end
		EmitSoundOn("Sound_THTD.thtd_star_up_fail",caster)
		local player = caster:GetPlayerOwner()
		if player then			
			if caster:GetNumItemsInInventory() >= THTD_MAX_ITEM_SLOT then 
				CustomGameEventManager:Send_ServerToPlayer(player, "display_custom_error", {msg="not_enough_item_slot"})
			end
		end
		return 
	end
	
	local drawList = {}
	drawList[2] = {}
	drawList[3] = {}
	drawList[4] = {}

	for k,v in pairs(towerPlayerList[caster:GetPlayerOwnerID()+1]) do
		if v["quality"] == 2 and v["itemName"] ~= "BonusEgg" then
			for i=1,v["count"] do
				table.insert(drawList[2],v["itemName"])
			end
		elseif v["quality"] == 3 and v["itemName"] ~= "BonusEgg" then
			for i=1,v["count"] do
				table.insert(drawList[3],v["itemName"])
			end
		elseif v["quality"] == 4 and v["itemName"] ~= "BonusEgg" then
			for i=1,v["count"] do
				table.insert(drawList[4],v["itemName"])
			end
		end
	end

	local ssrChance = 5
	local srChance = 20	

	local chance = RandomInt(1,100)
	if caster.thtd_chance_count["SSR"] == nil then 
		caster.thtd_chance_count["SSR"] = 0
	end
	if caster.thtd_chance_count["SSR"] >= 100/ssrChance then 
		chance = 1
	end
	if chance > ssrChance then
		caster.thtd_chance_count["SSR"] = caster.thtd_chance_count["SSR"] + 1
	end

	local itemName = nil
	if chance <= ssrChance then
		caster.thtd_chance_count["SSR"] = 0
		if #drawList[4] > 0 then
			itemName = drawList[4][RandomInt(1,#drawList[4])]
		else
			THTD_ModifyGoldEx(caster:GetPlayerOwnerID(), 5000 , true, DOTA_ModifyGold_SellItem) 
		end
	elseif chance <= (ssrChance + srChance) then
		if #drawList[3] > 0 then
			itemName = drawList[3][RandomInt(1,#drawList[3])]
		else
			THTD_ModifyGoldEx(caster:GetPlayerOwnerID(), 2500 , true, DOTA_ModifyGold_SellItem) 
		end
	else
		if #drawList[2] > 0 then
			itemName = drawList[2][RandomInt(1,#drawList[2])]
		else
			THTD_ModifyGoldEx(caster:GetPlayerOwnerID(), 1000 , true, DOTA_ModifyGold_SellItem) 
		end
	end		
	if caster:THTD_AddCardPoolItem(itemName) == false then 
		if keys.ability:IsItem()==false then
			PlayerResource:ModifyGold(caster:GetPlayerOwnerID(), keys.ability:GetGoldCost(keys.ability:GetLevel()-1) , true, DOTA_ModifyGold_SellItem) 
		end
		return
	end	

	if GameRules.player_bb_buff[playerid]["item_3012"] > 0 and RollPercentage(GameRules.player_bb_buff[playerid]["item_3012"]) then
		local quality = towerNameList[itemName]["quality"]
		local itemBonus = nil
		if quality == 2 then 
			itemBonus = CreateItem("item_2004", nil, nil)
		elseif quality == 3 then 
			itemBonus = CreateItem("item_2003", nil, nil)
		elseif quality == 4 then 
			itemBonus = CreateItem("item_2002", nil, nil)
		end
		if itemBonus ~= nil then	
			itemBonus.owner_player_id = playerid
			itemBonus:SetPurchaser(caster)
			itemBonus:SetPurchaseTime(1.0)
			
			if caster:GetNumItemsInInventory() >= THTD_MAX_ITEM_SLOT then 
				CreateItemOnPositionSync(caster:GetAbsOrigin(), itemBonus)
			else
				caster:AddItem(itemBonus)
			end		
		end	
	end

	if keys.ability:IsItem() then
		local charge = keys.ability:GetCurrentCharges()
		if charge > 1 then
			keys.ability:SetCurrentCharges(charge-1)
		else
			caster:RemoveItem(keys.ability)
		end
	else		
		if GameRules.player_bb_buff[playerid]["item_3018"] < 1 then 
			PlayerResource:ModifyGold(playerid, math.floor((keys.ability:GetGoldCost(keys.ability:GetLevel()-1)) * (1 - GameRules.player_bb_buff[playerid]["item_3018"])) , true, DOTA_ModifyGold_SellItem) 
		end
	end

	drawList = {}
end

local itemReplaceOrigin = 
{
	[1] = Vector(-2100,3540,144),
	[2] = Vector(1830,3540,144),
	[3] = Vector(1830,-2300,144),
	[4] = Vector(-2100,-2300,144)
}

function SortItem(keys)
	local caster = keys.caster
	local playerid = caster:GetPlayerOwnerID()

	-- 弹出储藏处物品
	if caster:GetNumItemsInStash() > 0 then
		for i=THTD_MAX_ITEM_SLOT,THTD_ITEM_TPSCROLL_SLOT-1 do
			local targetItem = caster:GetItemInSlot(i)
			if targetItem ~= nil and targetItem:IsNull() == false then						
				caster:EjectItemFromStash(targetItem)
				local box = targetItem:GetContainer()
				if box ~= nil then 							
					box:SetAbsOrigin(caster.spawn_position)
				end
			end
		end				
	end		

	local sortedItemPos = {}
	local iH = 0
	local iV = 0
	local items = Entities:FindAllByClassname("dota_item_drop")
	table.sort(items, function(a,b) 
		local aItem = a:GetContainedItem()
		local bItem = b:GetContainedItem()				
		if aItem ~= nil and bItem == nil then return true end
		if aItem == nil and bItem ~= nil then return false end
		if aItem == nil and bItem == nil then return true end
		if aItem:IsStackable() == true and bItem:IsStackable() == false then return true end
		if aItem:IsStackable() == false and bItem:IsStackable() == true then return false end		
		local aName = aItem:GetAbilityName()
		local bName = bItem:GetAbilityName()
		if string.sub(aName,1,6) ~= "item_3" and string.sub(bName,1,6) == "item_3" then return true end
		if string.sub(aName,1,6) == "item_3" and string.sub(bName,1,6) ~= "item_3" then return false end
		if string.sub(aName,1,6) == "item_3" and string.sub(bName,1,6) == "item_3" then return tonumber(string.sub(aName,7,9)) < tonumber(string.sub(bName,7,9)) end
		local aData = towerNameList[aName]
		local bData = towerNameList[bName]							
		if aData ~= nil and bData == nil then return true end
		if aData == nil and bData ~= nil then return false end
		if aData == nil and bData == nil then return aName < bName end
		if aData["cardname"] == "BonusEgg" and bData["cardname"] ~= "BonusEgg" then return true end
		if aData["cardname"] ~= "BonusEgg" and bData["cardname"] == "BonusEgg" then return false end
		if string.sub(aData["cardname"],1,5) == "item_" and string.sub(bData["cardname"],1,5) ~= "item_" then return true end
		if string.sub(aData["cardname"],1,5) ~= "item_" and string.sub(bData["cardname"],1,5) == "item_" then return false end
		return (aData["quality"] > bData["quality"])			
	end)	
	for _,v in pairs(items) do
		local containedItem = v:GetContainedItem()				 			
		if containedItem.locked_by_player_id == nil and (containedItem.owner_player_id == playerid or (containedItem:GetPurchaser() ~= nil and containedItem:GetPurchaser():GetPlayerOwnerID() == playerid)) then 				
			local itemName = containedItem:GetAbilityName()
			if sortedItemPos[itemName] == nil then			
				sortedItemPos[itemName] = GetSpawnLineOffsetVector(caster.spawn_index, itemReplaceOrigin[caster.spawn_index], iH * 200, iV * 200)										
				if iH < 9 then 							
					iH = iH + 1
				else							
					iH = 0
					iV = iV + 1
				end						
			end
			v:SetAbsOrigin(sortedItemPos[itemName])
			THTD_ItemSetScale(containedItem)
		end				
	end	
	sortedItemPos = {}
end

function OnIntervalThinkAutoCast(keys)
	if keys.ability:GetAutoCastState() then 
		if keys.ability:GetLevel() ~= 2 then 
			keys.ability:SetLevel(2)
		end
	else
		if keys.ability:GetLevel() ~= 1 then 
			keys.ability:SetLevel(1)
		end
	end
end

function BuyEgg(keys)
	local caster = keys.caster
	local hero = caster:GetHero()

	if hero:GetNumItemsInInventory() >= THTD_MAX_ITEM_SLOT then 
		PlayerResource:ModifyGold(hero:GetPlayerOwnerID(), keys.ability:GetGoldCost(keys.ability:GetLevel()-1) , true, DOTA_ModifyGold_SellItem) 
		CustomGameEventManager:Send_ServerToPlayer(hero:GetPlayerOwner(), "display_custom_error", {msg="not_enough_item_slot"})
		return
	end

	caster:EmitSound("Sound_THTD.thtd_buy")

	local item = CreateItem(keys.item_name, hero, hero)
	if item ~= nil then
		item.owner_player_id = hero.thtd_player_id
		hero:AddItem(item)
	else
		PlayerResource:ModifyGold(hero:GetPlayerOwnerID(), keys.ability:GetGoldCost(keys.ability:GetLevel()-1) , true, DOTA_ModifyGold_SellItem) 
	end		
end

local roll_card_type = 
{
	[1] = {
		["Level1"] = 1,
	},
	[2] = {
		["Level1"] = 2,
	},
	[3] = {
		["Level2"] = 3,
	},
	[4] = {
		["Level2"] = 3,
		["Level3"] = 1,
	},
	[5] = {
		["Level3"] = 5,
	},
}

function RollCard(keys)
	local caster = keys.caster
	local hero = caster:GetHero()
	local level = keys.ability:GetLevel() + 2

	caster:EmitSound("UI.Xidd")
		
	if hero.is_game_over == true then 
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="hero_is_game_over"})
		return
	end

	if caster.roll_card_count == nil then 
		caster.roll_card_count = 0
	end

	if caster.roll_card_count >= 50 then 
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="roll_card_reach_to_max"})
		PlayerResource:ModifyGold(caster:GetPlayerOwnerID(), keys.ability:GetGoldCost(keys.ability:GetLevel()-1) , true, DOTA_ModifyGold_SellItem) 
		return
	end

	if caster.roll_card_count >= SpawnSystem.CurWave then 		
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="roll_card_reach_to_wave"})
		PlayerResource:ModifyGold(caster:GetPlayerOwnerID(), keys.ability:GetGoldCost(keys.ability:GetLevel()-1) , true, DOTA_ModifyGold_SellItem) 
		return
	end

	caster.roll_card_count = caster.roll_card_count + 1
	print("----- roll_card_count : ", caster.roll_card_count)	

	local count = 0
	for k,v in pairs(roll_card_type[level]) do
		if k == "Level1" then
			local drawList = {}

			drawList[1] = {}
			for k,v in pairs(towerNameList) do
				if v["quality"] == 1 and v["cardname"] ~= "BonusEgg" then
					table.insert(drawList[1],k)
				end
			end

			for i=1,v do
				local item = CreateItem(drawList[1][RandomInt(1,#drawList[1])], nil, nil)				
				if item ~= nil then		
					item.owner_player_id = hero.thtd_player_id
					item:SetPurchaser(hero)
					item:SetPurchaseTime(1.0)
					local origin = GetSpawnLineOffsetVector(hero.spawn_index, hero.spawn_position, count * 130, -150)					
					local effectIndex = ParticleManager:CreateParticle("particles/heroes/thtd_shinki/ability_shinki_01.vpcf", PATTACH_CUSTOMORIGIN, nil)
					ParticleManager:SetParticleControl(effectIndex, 0, origin - Vector(0,0,750))
					ParticleManager:DestroyParticleSystem(effectIndex,false)
					caster:SetContextThink(DoUniqueString("thtd_shinki_01_effect_wait"), 
						function()
							if GameRules:IsGamePaused() then return 0.03 end
							CreateItemOnPositionSync(origin,item)
							THTD_ItemSetScale(item)
							return nil
						end,
					3.0)
					count = count + 1
				end
			end
			
		elseif k == "Level2" then
			local drawList = {}

			drawList[1] = {}
			drawList[2] = {}

			for k,v in pairs(towerNameList) do
				if v["quality"] == 1 and v["cardname"] ~= "BonusEgg" then
					table.insert(drawList[1],k)
				elseif v["quality"] == 2 and v["cardname"] ~= "BonusEgg" and v["cardname"] ~= "item_2021" then
					table.insert(drawList[2],k)
				end
			end

			for i=1,v do
				local chance = RandomInt(0,100)
				local item = nil
				if chance <=20 then
					if #drawList[2] > 0 then
						item = CreateItem(drawList[2][RandomInt(1,#drawList[2])], nil, nil)						
					end
				elseif chance > 20 then
					if #drawList[1] > 0 then
						item = CreateItem(drawList[1][RandomInt(1,#drawList[1])], nil, nil)						
					end
				end

				if item~=nil then		
					item.owner_player_id = hero.thtd_player_id
					item:SetPurchaser(hero)
					item:SetPurchaseTime(1.0)
					local origin
					if string.sub(item:GetAbilityName(), 1, 6) == "item_2" then
						origin = GetSpawnLineOffsetVector(hero.spawn_index, hero.spawn_position, count * 130, 0)	
					else						
						origin = GetSpawnLineOffsetVector(hero.spawn_index, hero.spawn_position, count * 130, -150)		
					end	
					local effectIndex = ParticleManager:CreateParticle("particles/heroes/thtd_shinki/ability_shinki_01.vpcf", PATTACH_CUSTOMORIGIN, nil)
					ParticleManager:SetParticleControl(effectIndex, 0, origin - Vector(0,0,750))
					ParticleManager:DestroyParticleSystem(effectIndex,false)
					caster:SetContextThink(DoUniqueString("thtd_shinki_01_effect_wait"), 
						function()
							if GameRules:IsGamePaused() then return 0.03 end
							CreateItemOnPositionSync(origin,item)
							THTD_ItemSetScale(item)
							return nil
						end,
					3.0)
					count = count + 1
				end
			end

		elseif k == "Level3" then
			local drawList = {}

			drawList[2] = {}
			drawList[3] = {}
			drawList[4] = {}

			for k,v in pairs(towerNameList) do
				if v["quality"] == 2 and v["cardname"] ~= "BonusEgg" and v["cardname"] ~= "item_2021" then
					table.insert(drawList[2],k)
				elseif v["quality"] == 3 and v["cardname"] ~= "BonusEgg" and v["cardname"] ~= "item_2022" and v["cardname"] ~= "item_2001" then
					table.insert(drawList[3],k)
				elseif v["quality"] == 4 and v["cardname"] ~= "BonusEgg" then
					table.insert(drawList[4],k)
				end
			end

			for i=1,v do
				local chance = RandomInt(1,100)

				if caster.thtd_chance_count == nil then 
					caster.thtd_chance_count = {}
				end
				if caster.thtd_chance_count["shinki_SSR"] == nil then 
					caster.thtd_chance_count["shinki_SSR"] = 0
				end
				if caster.thtd_chance_count["shinki_SSR"] >= 20 then 
					chance = 0
				end
				if chance > 5 then
					caster.thtd_chance_count["shinki_SSR"] = caster.thtd_chance_count["shinki_SSR"] + 1
				end

				local item = nil
				if chance <=5 then
					caster.thtd_chance_count["shinki_SSR"] = 0
					if #drawList[4] > 0 then
						item = CreateItem(drawList[4][RandomInt(1,#drawList[4])], nil, nil)						
					end
				elseif chance <= 25 then
					if #drawList[3] > 0 then
						item = CreateItem(drawList[3][RandomInt(1,#drawList[3])], nil, nil)
					end
				elseif chance > 25 then
					if #drawList[2] > 0 then
						item = CreateItem(drawList[2][RandomInt(1,#drawList[2])], nil, nil)
					end
				end

				if item~=nil then
					item.owner_player_id = hero.thtd_player_id
					item:SetPurchaser(hero)
					item:SetPurchaseTime(1.0)
					local origin
					if string.sub(item:GetAbilityName(), 1, 6) == "item_2" then
						origin = GetSpawnLineOffsetVector(hero.spawn_index, hero.spawn_position, count * 130, 0)
					else
						if item:THTD_GetCardQuality() == 4 then 
							origin = GetSpawnLineOffsetVector(hero.spawn_index, hero.spawn_position, count * 130, -150*2)
						else
							origin = GetSpawnLineOffsetVector(hero.spawn_index, hero.spawn_position, count * 130, -150)
						end
					end
					local effectIndex = ParticleManager:CreateParticle("particles/heroes/thtd_shinki/ability_shinki_01.vpcf", PATTACH_CUSTOMORIGIN, nil)
					ParticleManager:SetParticleControl(effectIndex, 0, origin - Vector(0,0,750))
					ParticleManager:DestroyParticleSystem(effectIndex,false)
					caster:SetContextThink(DoUniqueString("thtd_shinki_01_effect_wait"), 
						function()
							if GameRules:IsGamePaused() then return 0.03 end
							CreateItemOnPositionSync(origin,item)
							THTD_ItemSetScale(item)
							return nil
						end,
					3.0)
					count = count + 1
				end
			end
		end
	end	

	if caster.roll_card_count == 8 then 
		keys.ability:SetLevel(2)
	elseif caster.roll_card_count == 16 then 
		keys.ability:SetLevel(3)
	end
end

function SkipWave(keys)	
	local caster = keys.caster
	local hero = caster:GetHero()

	local goldCost = keys.ability:GetGoldCost(keys.ability:GetLevel()-1)
	local keyCount = keys.ability:GetSpecialValueFor("count")
	
	if not SpawnSystem.IsUnLimited then 
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="only_unlimited_wave"})
		PlayerResource:ModifyGold(hero:GetPlayerOwnerID(), goldCost, true, DOTA_ModifyGold_SellItem)
		return
	end
	if SpawnSystem.ReachToWave ~= nil then
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="skip_wave_exist"})	
		PlayerResource:ModifyGold(hero:GetPlayerOwnerID(), goldCost, true, DOTA_ModifyGold_SellItem)
		return
	end

	local count = 0 
	local hTPSlotItem = hero:GetItemInSlot(DOTA_ITEM_TP_SCROLL)
	if hTPSlotItem then			
		count = hTPSlotItem:GetCurrentCharges()
	end
	if keyCount > 0 then	
		if count < keyCount then 
			PlayerResource:ModifyGold(hero:GetPlayerOwnerID(), goldCost, true, DOTA_ModifyGold_SellItem) 
			CustomGameEventManager:Send_ServerToPlayer(hero:GetPlayerOwner(), "display_custom_error", {msg="not_enough_key_count"})
			return
		end	
		count = count - keyCount
		if count <= 0 then
			hTPSlotItem:RemoveSelf()
		else
			hTPSlotItem:SetCurrentCharges(count)
		end
		Service:SaveKeyCount(hero.thtd_player_id)
	end
	
	SpawnSystem.ReachToWave = SpawnSystem.CurWave - 50 + keys.AddWave
	if SpawnSystem.CurWave <= 150 and SpawnSystem.ReachToWave > 100 then
		SpawnSystem:RemoveBoss()
	end
	
	CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_chat_msg", {msg="skip_wave_tip", params={player_name=PlayerResource:GetPlayerName(caster:GetPlayerOwnerID()),item_name=keys.ItemName,wave=SpawnSystem.ReachToWave}})	
	EmitAnnouncerSound("Quest.Completed")
end

local bonus_tower_table = 
{
	"minoriko",
	"nazrin",
	"lily",
	"daiyousei",
	"sizuha",
	"toramaru",
	"seiga",
}

function IsBonusTower(itemName, isUnit)
 	local towerName
	if isUnit == true then 
		towerName = itemName
	else
		towerName = towerNameList[itemName]["cardname"]
	end
	for k,v in pairs(bonus_tower_table) do 
		if v == towerName then 
			return true
		end
	end
	return false
end

function GetBonusTowerCount(hero)
	local count = 0
	for k,v in pairs(hero.thtd_hero_tower_list) do
		if IsBonusTower(v:GetUnitName(), true) then
			count = count + 1
		end
	end
	return count
end

function AddManaRegenPercentage(keys)
	keys.caster:THTD_AddManaRegenPercentage(keys.mana_regen, "ability_common_mana_regen_bonus")	
end

function AddPowerAttackPercentage(keys)
	keys.caster:THTD_AddPowerPercentage(keys.power_up, "ability_common_power_bonus")
	keys.caster:THTD_AddAttackPercentage(keys.power_up, "ability_common_power_bonus")	
end

function AddAttackSpeed(keys)
	keys.caster:THTD_AddAttackSpeed(keys.attack_speed, "ability_common_attack_speed", true)	
end

function OnEquipItem(keys)
	local caster = keys.caster
	local item = keys.ability
	print()
	print("-----"..caster:GetUnitName().." equip "..item:GetAbilityName())
	-- 不延时有bug
	if caster:THTD_IsTower() then
		caster:SetContextThink(DoUniqueString("dota_timer"), 
			function() 
				if GameRules:IsGamePaused() then return 0.06 end
				caster:ItemEquipBonus(item)
				return nil 
			end, 
		0.15)
	end
end

function OnUnequipItem(keys)
	local caster = keys.caster
	local item = keys.ability
	print()
	print("-----"..caster:GetUnitName().." unequip "..item:GetAbilityName())
	if caster:THTD_IsTower() then
		caster:SetContextThink(DoUniqueString("dota_timer"), 
			function() 
				if GameRules:IsGamePaused() then return 0.06 end
				caster:ItemEquipBonus(item)
				return nil 
			end, 
		0.15)
	end
end

function OnCloseAI(keys)
	local caster = keys.caster

	-- local base_power = caster.thtd_attack
	-- local percentage = caster:THTD_GetAttackPercentage()
	-- local bonus_power = math.floor(base_power * percentage/100)
	-- print("----percentage : ", tostring(percentage).."%")
	-- print("base attack : ", base_power)
	-- print("bonus attack : ", bonus_power)
	print("crit : ", caster:THTD_GetCritDamage())
	print("chance : ", caster:THTD_GetCritChance())

	if caster.thtd_close_ai ~= true then
		caster.thtd_close_ai = true		
		CustomGameEventManager:Send_ServerToPlayer( caster:GetPlayerOwner() , "show_message", {msg="change_to_close_ai", duration=5, params={}, color="#0ff"} )		
	else
		caster.thtd_close_ai = false		
		CustomGameEventManager:Send_ServerToPlayer( caster:GetPlayerOwner() , "show_message", {msg="change_to_open_ai", duration=5, params={}, color="#0ff"} )
		-- 神子和幽幽子，是否开启大招
		local unitName = caster:GetUnitName()
		if unitName=="miko" then 
			CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner() , "ai_skill_enable", {entity=caster:GetEntityIndex(), name=unitName, skill=4})
			-- thtd_miko_04_cast
		elseif unitName=="yuyuko" then		
			CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner() , "ai_skill_enable", {entity=caster:GetEntityIndex(), name=unitName, skill=3})
			-- thtd_yuyuko_03_cast		
		elseif unitName=="keine" then		
			CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner() , "ai_skill_enable", {entity=caster:GetEntityIndex(), name=unitName, skill=2})
			-- thtd_keine_02_cast		
		elseif unitName=="patchouli" then		
			CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner() , "ai_skill_enable", {entity=caster:GetEntityIndex(), name=unitName, skill=2})
			-- thtd_patchouli_02_cast
		end		
	end
end

-- 定点施放技能
function OnCastPointAI(keys)
	local caster = EntIndexToHScript(keys.caster_entindex)
	local targetPoint = keys.target_points[1]	
	local range = GetDistanceBetweenTwoVec2D(caster:GetOrigin(), targetPoint)
	if range <= 100 then
		caster.thtd_last_cast_point = nil
		CustomGameEventManager:Send_ServerToPlayer( caster:GetPlayerOwner() , "show_message", {msg="change_to_close_cast_on_fixed_point", duration=5, params={}, color="#0ff"} )
	elseif range > keys.ability:GetCastRange() then		
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="cast_range_out"})
	else
		caster.thtd_last_cast_point = targetPoint
		CustomGameEventManager:Send_ServerToPlayer( caster:GetPlayerOwner() , "show_message", {msg="change_to_open_cast_on_fixed_point", duration=5, params={}, color="#0ff"} )					
	end
end

-- 玩具
function OnSpellStartCosmetic( event )
    local caster = event.caster
    local abilityname = event.Ability    
	local ability = caster:AddAbility(abilityname)
	-- 所有玩具技能清单在官方的PUI的images\spellicons\consumables下同名称
	ability:SetLevel(1)
	ability:EndCooldown()	
	ability:SetHidden(true)
	ability:CastAbility()	
	caster:SetContextThink(DoUniqueString("dota_timer"), 
		function() 			
			caster:RemoveAbility(abilityname)
			return nil 
		end, 
	0.3)	 
end

-- 礼物包
function OnSpellStartBundle( keys )
    local caster = keys.caster   
	local playerid = caster:GetPlayerOwnerID()

	if not caster:IsRealHero() then 
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="only_hero_use"})
		keys.ability:EndCooldown()
		return
	end

	if caster:GetNumItemsInInventory() > 6 then 
		CustomGameEventManager:Send_ServerToPlayer(caster:GetPlayerOwner(), "display_custom_error", {msg="not_enough_item_slot"})			
		return 
	end

	keys.ability:RemoveSelf()
	-- caster:AddItemByName(keys.Item1)
	-- caster:AddItemByName(keys.Item2)
	-- caster:AddItemByName(keys.Item3)
	-- caster:AddItemByName(keys.Item4)
	for i=1,4 do
		local item = CreateItem(keys["Item"..tostring(i)], nil, nil)
		if item ~= nil then
			item.owner_player_id = playerid			
			caster:AddItem(item)
		end
	end
end

function IsMaxCountCheckOK(hero, itemName)
	local towerName =  towerNameList[itemName]["cardname"]
	local quality = towerNameList[itemName]["quality"]
	local maxCount = (5 - quality) * 2

	maxCount = math.floor(maxCount * (1 + (GameRules.player_bb_buff[hero.thtd_player_id]["item_3020"] or 0)/100))

	if quality > 1 then
		local count = 0
		for k,v in pairs(hero.thtd_hero_tower_list) do
			if v:GetUnitName() == towerName then
				count = count + 1
			end			
		end
		if count >= maxCount then
			return false
		else
			return true
		end
	else
		return true
	end   
end

function OnCreatedDecreaseArmor(keys)	
	keys.target:AddPhysicalArmor(-keys.armor)
end

function OnDestroyDecreaseArmor(keys)		
	keys.target:AddPhysicalArmor(keys.armor)
end

function OnCreatedDecreaseMagicArmor(keys)	
	keys.target:AddMagicalResist(-keys.magic_armor)
end

function OnDestroyDecreaseMagicArmor(keys)		
	keys.target:AddMagicalResist(keys.magic_armor)
end
