if SpawnSystem == nil then
	SpawnSystem = {}
	SpawnSystem.Spawner = {}   -- 刷怪基本数据
	SpawnSystem.AttackingSpawner = {}  -- 刷怪实体	
	SpawnSystem.CurWave = 0  -- 当前波数
	SpawnSystem.CurTime = 0  -- 当前时间
	SpawnSystem.IsUnLimited = false  -- 是否无尽
	SpawnSystem.ReachToWave = nil	--跳关
	SpawnSystem.RankMinWave = 130	--开始计算排行榜的波数
	SpawnSystem.GameOverPlayerId = {}  -- 失败玩家id

	SpawnSystem.SpawnOrigin =  -- 玩家出生地点
	{
		[1] = Vector(-3424,2816,144),
		[2] = Vector(3424,2816,144),
		[3] = Vector(3424,-2816,144),
		[4] = Vector(-3424,-2816,144)
	}	
	SpawnSystem.ShopOrigin =  -- 玩家商店地点
	{
		[1] = Vector(-2454,2989,142),
		[2] = Vector(2227,2922,142),
		[3] = Vector(2259,-2806,142),
		[4] = Vector(-2454,-2867,142)
	}
	SpawnSystem.ShopForward =  -- 玩家商店朝向
	{
		[1] = Vector(-math.cos(math.pi/4),-math.sin(math.pi/4),0),
		[2] = Vector(math.cos(math.pi/4),-math.sin(math.pi/4),0),
		[3] = Vector(math.cos(math.pi/4),math.sin(math.pi/4),0),
		[4] = Vector(-math.cos(math.pi/4),math.sin(math.pi/4),0)
	}
end

NORMAL_MODE = 1
EXTRA_MODE = 2
UNLIMITED_MODE = 3
RANDOM_MODE = 4
CHALLENGE_MODE = 5
FUNNY_MODE = 6
PVE_MODE = 7

MAX_HEALTH = 2000000000

THTD_EntitiesRectInner = { [0] = {}, [1] = {}, [2] = {},[3] = {} }  -- 内圈怪按玩家逄
THTD_EntitiesRectOuter = { }  -- 外圈怪统一算
thtd_bosses_list = 
{
	"alice",
	"aya",
	"hina",
	"kaguya",
	"keine",
	"kisume",
	"marisa",
	"minoriko",
	"mokou",
	"rumia",
	"yuugi",
}

function SpawnSystem:GetCount()	
	local spawner = SpawnSystem.AttackingSpawner	
	if spawner == nil or #spawner == 0 then return 0 end
	local i = 0
	for _, spawnerLine in pairs(spawner) do	
		if spawnerLine.hero.is_game_over ~= true then
			i = i + 1			
		end
	end		
	return i
end


function RefreshItemListNetTable(hero)
	if hero == nil or hero.is_game_over == true then return end
	hero.thtd_hero_damage_list = {}
	for k,v in pairs(hero.thtd_hero_tower_list) do		
		hero.thtd_hero_damage_list[tostring(v:GetEntityIndex())] = math.floor(v:THTD_GetTowerDamage())	
	end	
	local steamid = PlayerResource:GetSteamID(hero:GetPlayerOwnerID())	
	CustomNetTables:SetTableValue("TowerListInfo", "damagelist"..tostring(steamid), hero.thtd_hero_damage_list)	
	CustomNetTables:SetTableValue("CustomGameInfo", "game_info"..tostring(steamid), hero.thtd_game_info)
end

function RefreshItemListNetTableAll()	
	if SpawnSystem.AttackingSpawner == nil or #SpawnSystem.AttackingSpawner == 0 then return end
	for k,v in pairs(SpawnSystem.AttackingSpawner) do		
		RefreshItemListNetTable(v.hero)
	end
end



-- todo 使用buff的think实现

function RefreshHeroBuff3011(hero)
	if GameRules.player_bb_buff[hero.thtd_player_id]["item_3011"] <= 0 and GameRules.player_bb_buff[hero.thtd_player_id]["item_3011_effect"] <= 0 then 
		return 
	end

	local targets = {}
	local comboCount = 0
	local hasSatori = false
	local hasKoishi = false
	local hasRin = false
	local hasUtsuho = false	
	for _,tower in pairs(hero.thtd_hero_tower_list) do
		local unitName = tower:GetUnitName()
		if unitName == "satori" then
			hasSatori = true
			table.insert(targets, tower)
		elseif unitName == "koishi" then
			hasKoishi = true
			table.insert(targets, tower)
		elseif unitName == "rin" then
			hasRin = true
			table.insert(targets, tower)
		elseif unitName == "utsuho" then
			hasUtsuho = true
			table.insert(targets, tower)
		end
	end
	if hasSatori and hasKoishi then 
		comboCount = comboCount + 1
	end
	if hasRin and hasUtsuho then 
		comboCount = comboCount + 1
	end
	
	GameRules.player_bb_buff[hero.thtd_player_id]["item_3011_effect"] = GameRules.player_bb_buff[hero.thtd_player_id]["item_3011"] * comboCount
	
	if GameRules.player_bb_buff[hero.thtd_player_id]["item_3011_effect"] > 0 then 		
		for k,v in pairs(targets) do
			if not v:HasModifier("modifier_bb_buff_3011_effect") then
				v:AddNewModifier(v, nil, "modifier_bb_buff_3011_effect", nil)
			elseif v.thtd_hero_3011_damage_up  ~= GameRules.player_bb_buff[hero.thtd_player_id]["item_3011_effect"] then
				v:RemoveModifierByName("modifier_bb_buff_3011_effect")	
				v:AddNewModifier(v, nil, "modifier_bb_buff_3011_effect", nil)
			end
		end
	else
		for k,v in pairs(targets) do
			if v:HasModifier("modifier_bb_buff_3011_effect") then
				v:RemoveModifierByName("modifier_bb_buff_3011_effect")			
			end
		end
	end
end

function RefreshHeroBuff3015(hero)
	if GameRules.player_bb_buff[hero.thtd_player_id]["item_3015"] <= 0 and GameRules.player_bb_buff[hero.thtd_player_id]["item_3015_effect"] <= 0 then 
		return 
	end

	local targets = {}
	local count = 0
	local hasEirin = false
	local hasKaguya = false
	local hasReisen = false
	local hasInaba = false	
	for _,tower in pairs(hero.thtd_hero_tower_list) do
		local unitName = tower:GetUnitName()
		if unitName == "eirin" then
			hasEirin = true
			table.insert(targets, tower)
		elseif unitName == "kaguya" then
			hasKaguya = true
			table.insert(targets, tower)
		elseif unitName == "reisen" then
			hasReisen = true
			table.insert(targets, tower)
		elseif unitName == "inaba" then
			hasInaba = true
			table.insert(targets, tower)
		end
	end
	if hasEirin then 
		count = count + 1
	end
	if hasKaguya then 
		count = count + 1
	end
	if hasReisen then 
		count = count + 1
	end
	if hasInaba then 
		count = count + 1
	end	
	
	GameRules.player_bb_buff[hero.thtd_player_id]["item_3015_effect"] = GameRules.player_bb_buff[hero.thtd_player_id]["item_3015"] * count
	
	if GameRules.player_bb_buff[hero.thtd_player_id]["item_3015_effect"] > 0 then 		
		for k,v in pairs(targets) do
			if not v:HasModifier("modifier_bb_buff_3015_effect") then
				v:AddNewModifier(v, nil, "modifier_bb_buff_3015_effect", nil)
			elseif v.thtd_hero_3015_damage_up  ~= GameRules.player_bb_buff[hero.thtd_player_id]["item_3015_effect"] then
				v:RemoveModifierByName("modifier_bb_buff_3015_effect")	
				v:AddNewModifier(v, nil, "modifier_bb_buff_3015_effect", nil)
			end
		end
	else
		for k,v in pairs(targets) do
			if v:HasModifier("modifier_bb_buff_3015_effect") then
				v:RemoveModifierByName("modifier_bb_buff_3015_effect")			
			end
		end
	end
end

function RefreshHeroBuff3028(hero)	
	if GameRules.player_bb_buff[hero.thtd_player_id]["item_3028"] <= 0 and GameRules.player_bb_buff[hero.thtd_player_id]["item_3028_effect"] <= 0 then 
		return 
	end

	local targets = {}	
	for _,tower in pairs(hero.thtd_hero_tower_list) do
		local unitName = tower:GetUnitName()
		if unitName == "yuugi" or unitName == "suika" then		
			table.insert(targets, tower)		
		end
	end
	
	GameRules.player_bb_buff[hero.thtd_player_id]["item_3028_effect"] = GameRules.player_bb_buff[hero.thtd_player_id]["item_3028"]
	
	if GameRules.player_bb_buff[hero.thtd_player_id]["item_3028_effect"] > 0 then 		
		for k,v in pairs(targets) do
			local ability = v:FindAbilityByName("faceless_void_time_lock")
			if ability == nil then
				ability = v:AddAbility("faceless_void_time_lock")
			end
			if ability:GetLevel() ~= GameRules.player_bb_buff[hero.thtd_player_id]["item_3028_effect"] then 
				ability:SetLevel(GameRules.player_bb_buff[hero.thtd_player_id]["item_3028_effect"])
				ability:SetActivated(true)
			end
		end
	else
		for k,v in pairs(targets) do
			if v:HasAbility("faceless_void_time_lock") then
				v:RemoveAbility("faceless_void_time_lock")
			end
		end
	end
end



-- 刷怪准备，DOTA_GAMERULES_STATE_PRE_GAME 时调用
function SpawnSystem:PreSpawn()
	-- 载入刷怪数据
	SpawnSystem.Spawner = LoadKeyValues("scripts/npc/Spawner.txt")

	-- 显示准备倒计时
	local maxTime = math.floor(GameRules:GetGameTime() + 0.5) + 30
	local uiWaveInfo = 
	{
		["Wave"] =  0,
		["RemainingTime"] =  maxTime		
	}	
	
	GameRules:GetGameModeEntity():SetContextThink(DoUniqueString("PreSpawn") ,
		function()
			if GameRules:IsGamePaused() then return 0.1 end
			if GameRules:State_Get() == DOTA_GAMERULES_STATE_GAME_IN_PROGRESS then return nil end
			if uiWaveInfo["RemainingTime"] == 0 then
				CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="item_locked_tip", duration=60, params={}, color="#ff0"})
				return nil 
			end
			uiWaveInfo["RemainingTime"] =  math.max(math.floor(maxTime - GameRules:GetGameTime()),0)
			SpawnSystem.CurTime = uiWaveInfo["RemainingTime"]
			CustomNetTables:SetTableValue("CustomGameInfo", "attacking_process", uiWaveInfo)			
			RefreshItemListNetTableAll()
			if (GameRules:IsCheatMode() and IsInToolsMode() == false) then -- or SERVER_KEY == "Invalid_NotOnDedicatedServer" then
				SpawnSystem:GameEnd()
				return nil
			end			

			-- 初始化刷怪点
			if uiWaveInfo["RemainingTime"] <= 25 and SpawnSystem:GetCount() == 0 then 
				SpawnSystem:SpawnLine()				
				SpawnSystem:RefreshCreepMaxCount()	
				SpawnSystem:SpawnChest()				
				-- SendMsg(0, "test_tip", "总伤害",90)
				-- 通知提示
				local difficulty = GameRules:GetCustomGameDifficulty()					
				if difficulty == CHALLENGE_MODE then 
					CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="challenge_game_on", duration=25, params={}, color="#ff0"})
				elseif difficulty >= FUNNY_MODE then 
					CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="funny_game_on", duration=25, params={}, color="#ff0"})
				end
			end

			-- 同步UI数据
			RefreshItemListNetTableAll()
			
			-- 提示
			if SpawnSystem.CurTime == 15 then 
				GameRules:SendCustomMessage("#game_keyboard_tip", DOTA_TEAM_GOODGUYS, 0)				
			elseif SpawnSystem.CurTime == 8 then 
				GameRules:SendCustomMessage("#power_view_tip", DOTA_TEAM_GOODGUYS, 0)				
			end					

			return 1
		end,
	0)
end

-- 绑定刷怪点
function SpawnSystem:SpawnLine()
	local spawner = SpawnSystem.AttackingSpawner
	local heroes = {}
	for k,v in pairs(GameRules.HeroList) do
		if v ~= nil then 
			table.insert(heroes, v)
		end
	end
	if heroes == nil or #heroes == 0 then return end
	table.sort(heroes, function(a,b) return (a.thtd_player_id < b.thtd_player_id) end)	
	local j = 1	
	for _,hero in pairs(heroes) do		
    	if hero.is_game_over ~= true then
			local entity = Entities:FindByName(nil, "spanwer_player"..tostring(j))
			if entity ~= nil then	
				entity.index = j			
				entity.hero = hero
				hero.spawn_index = j
				hero.spawn_position = SpawnSystem.SpawnOrigin[j]				
				if GetDistanceBetweenTwoVec2D(hero:GetAbsOrigin(), hero.spawn_position) > 1000 then 
					hero:SetAbsOrigin(hero.spawn_position)
					hero.shop:SetAbsOrigin(SpawnSystem.ShopOrigin[j])
					hero.shop:MoveToPosition(SpawnSystem.ShopOrigin[j]+SpawnSystem.ShopForward[j])
				end
				
				if j == 1 then
					entity.first_point = "corner_M1408_1056"
					entity.first_forward = "left"	
					entity.second_point = "corner_M2771_1056"
					entity.second_forward = "up"			
				elseif j == 2 then
					entity.first_point = "corner_1408_1056"
					entity.first_forward = "right"	
					entity.second_point = "corner_2771_1056"
					entity.second_forward = "up"						
				elseif j == 3 then
					entity.first_point = "corner_1408_M1056"
					entity.first_forward = "right"	
					entity.second_point = "corner_2771_M1056"
					entity.second_forward = "down"							
				elseif j == 4 then
					entity.first_point = "corner_M1408_M1056"
					entity.first_forward = "left"	
					entity.second_point = "corner_M2771_M1056"
					entity.second_forward = "down"				
				end	
				table.insert(spawner, entity)
				j = j + 1				
			end
		end
	end
end


-- 刷怪开始，DOTA_GAMERULES_STATE_GAME_IN_PROGRESS 时调用
function SpawnSystem:InitSpawn()
	local spawner = SpawnSystem.AttackingSpawner

	local max_time = 0
	local left_time = 0
	local uiWaveInfo = 
	{
		["Wave"] = 1,
		["RemainingTime"] = max_time	
	}	
	local wave = 0
	local difficulty = GameRules:GetCustomGameDifficulty()
	local GameMode = GameRules:GetGameModeEntity()	
	GameMode:SetContextThink(DoUniqueString("AttackSpawn"),
		function()			
			if GameRules:IsGamePaused() then return 0.1 end	

			-- 每波开始
			if left_time <= 0 then
				SpawnSystem:WaveEndForEach()							

				if SpawnSystem.ReachToWave ~= nil then 
					SpawnSystem.CurWave = SpawnSystem.ReachToWave + 50
					SpawnSystem.RankMinWave = SpawnSystem.CurWave + 4
					SpawnSystem.ReachToWave = nil
				elseif SpawnSystem.CurWave == 50 and difficulty >= CHALLENGE_MODE then 					
					SpawnSystem.CurWave = 50 + 70					
				elseif difficulty >= FUNNY_MODE and SpawnSystem.CurWave < 50 then 
					SpawnSystem.CurWave = SpawnSystem.CurWave + 2
				else						
					SpawnSystem.CurWave = SpawnSystem.CurWave + 1
				end				
				wave = SpawnSystem.CurWave

				if wave > 130 and wave < SpawnSystem.RankMinWave then
					GameRules:SendCustomMessage("#skip_wave_rank_tip", DOTA_TEAM_GOODGUYS, 0)				
				end	

				-- 普通和Extra胜利
				if difficulty < UNLIMITED_MODE and wave > 120 then
					SpawnSystem:GameEnd()					
					return nil
				end

				-- 无尽前提示
				if wave == 50 then
					CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="spawn_unlimited", duration=133, params={count=50}, color="#0ff"})					
				end	
				
				-- 进入无尽
				if wave > 50 and SpawnSystem.IsUnLimited == false then 
					SpawnSystem:StartUnlimited()
				end	

				-- 100波以后取消刷文文
				if wave == 151 then					
					SpawnSystem:RemoveBoss(true)					
				end

				-- 每波怪的计时
				if wave <= 51 then
					max_time = math.floor(SpawnSystem.Spawner["Attacking"]["Wave".. tostring(wave)]["BreakTime"]  +
										  SpawnSystem.Spawner["Attacking"]["Wave".. tostring(wave)]["Times"] 	 * 
										  SpawnSystem.Spawner["Attacking"]["Wave".. tostring(wave)]["Interval"]  + 0.5)	
				elseif max_time > 30 then 
					max_time = math.floor(SpawnSystem.Spawner["Attacking"]["Wave51"]["BreakTime"]  +
										  SpawnSystem.Spawner["Attacking"]["Wave51"]["Times"] 	 * 
										  SpawnSystem.Spawner["Attacking"]["Wave51"]["Interval"]  + 0.5)						
				end

				left_time = max_time					

				SpawnSystem:ClearRemovedSpawner()
				SpawnSystem:StartSpawn()											
			end

			-- 增加无尽准备时间
			if wave == 50 and SpawnSystem.IsUnLimited == false and left_time == 0.5 then
				SpawnSystem:WaveEndForEach()
				SpawnSystem:StartUnlimited() 
				max_time = 180.5
				left_time = max_time
				CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="start_unlimited", duration=180, params={}, color="#ff0"})
				if difficulty == CHALLENGE_MODE then
					CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="challenge_game_on", duration=180, params={}, color="#ff0"})
				elseif difficulty >= FUNNY_MODE then 
					CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="funny_game_on", duration=180, params={}, color="#ff0"})
				end
			end

			-- 更新进度
			left_time = left_time - 0.5		
			if wave == 50 and SpawnSystem.IsUnLimited then	
				uiWaveInfo["Wave"] = 0
			else
				uiWaveInfo["Wave"] = wave
			end	
			uiWaveInfo["RemainingTime"] = math.floor(left_time)			
			CustomNetTables:SetTableValue("CustomGameInfo", "attacking_process", uiWaveInfo)
			SpawnSystem.CurTime = uiWaveInfo["RemainingTime"]
	
			-- 检查漏怪
			if not SpawnSystem:CreepCheck() then			
				return nil
			end

			-- 同步UI数据		
			RefreshItemListNetTableAll()	
			
			if left_time%5 == 0 then 
				SpawnSystem:SpawnChest()
			end

			return 0.5
		end, 
	0) 
	
end

-- 进入无尽相关设置
function SpawnSystem:StartUnlimited()
	SpawnSystem.IsUnLimited = true 
	local entities = Entities:FindAllByClassname("npc_dota_creature")
	for k,v in pairs(entities) do
		local findNum =  string.find(v:GetUnitName(), 'creature')
		if findNum ~= nil and v~=nil and v:IsNull()==false and v:IsAlive() then
			v:ForceKill(false)
		end
	end	
	for _,hero in pairs(GameRules.HeroList) do
		if hero~=nil and hero:IsNull()==false and hero.is_game_over ~= true then
			hero.thtd_game_info["creature_kill_count"] = 0
			hero.thtd_minoriko_02_change = 0
		end
	end
	SpawnSystem:RefreshCreepMaxCount()
end

-- 无尽高波移除特定BOSS
function SpawnSystem:RemoveBoss(showMsg)
	if showMsg then
		GameRules:SendCustomMessage("#one_hundred_wave_tip", DOTA_TEAM_GOODGUYS, 0)	
	end
	for k,v in pairs(thtd_bosses_list) do
		if v == "aya" then
			table.remove(thtd_bosses_list, k)
			break
		end
	end
end

-- 漏怪检查,返回是否可接受范围内
function SpawnSystem:CreepCheck()
	local spawner = SpawnSystem.AttackingSpawner	
	if spawner == nil or #spawner == 0 then return true end	
	local wave = SpawnSystem.CurWave
	local difficulty = GameRules:GetCustomGameDifficulty()
	
	CheckPlayerConnect()

	-- 无尽前
	if not SpawnSystem.IsUnLimited then
		local count = 0
		for _,inner in pairs(THTD_EntitiesRectInner) do
			if inner ~= nil then count = count + #inner end
		end
		if THTD_EntitiesRectOuter ~= nil then count = count + #THTD_EntitiesRectOuter end
		local isEndGame = false
		for spawnerIndex,spawnerLine in pairs(spawner) do
			local hero = spawnerLine.hero    
			if hero.is_game_over ~= true then
				hero.thtd_game_info["creep_count"] = count
				if count > hero.thtd_game_info["creep_count_max"] and isEndGame == false then 	
					isEndGame = true
				end
			end
		end
		if isEndGame then 
			for spawnerIndex,spawnerLine in pairs(spawner) do
				local hero = spawnerLine.hero    
				if hero.is_game_over ~= true and hero.reimu_pet ~= nil and hero.reimu_pet.pet_level >= 2 then 					
					for i=0,5 do
						local targetItem = hero.reimu_pet:GetItemInSlot(i)				
						if targetItem~=nil and targetItem:IsNull()==false and targetItem:GetAbilityName() == "item_2001" then
							hero.reimu_pet:CastAbilityNoTarget(targetItem, hero:GetPlayerOwnerID())
							isEndGame = false
							break
						end
					end
					if not isEndGame then break end
				end
			end
			if not isEndGame then 
				for spawnerIndex,spawnerLine in pairs(spawner) do
					local hero = spawnerLine.hero    
					hero.thtd_game_info["creep_count"] = 0
				end
				return true
			else
				RefreshItemListNetTableAll()				
				SpawnSystem:GameEnd()
				return false
			end
		else
			return true
		end
	end

	-- 无尽波数	
	-- local entities = Entities:FindAllByClassname("npc_dota_creature")
	for spawnerIndex,spawnerLine in pairs(spawner) do
		local hero = spawnerLine.hero    
		if hero.is_game_over ~= true then
			local count = 0		

			-- for k,v in pairs(entities) do
			-- 	if v ~= nil and v:IsNull() == false and v:IsAlive() and v.thtd_player_index == hero.thtd_player_id and v:GetHealth() > 0 then
			-- 		if string.find(v:GetUnitName(), 'creature_unlimited') ~= nil or string.find(v:GetUnitName(), 'creature_bosses') ~= nil then 					
			-- 			count = count + 1
			-- 		end	
			-- 	end
			-- end		
			
			-- 方法二，可以去掉 entities
			for k,v in pairs(THTD_EntitiesRectInner[hero.thtd_player_id]) do
				if v ~= nil and v:IsNull() == false and v:IsAlive() and v:GetHealth() > 0 then
					count = count + 1
				end
			end
			for k,v in pairs(THTD_EntitiesRectOuter) do
				if v ~= nil and v:IsNull() == false and v:IsAlive() and v.thtd_player_index == hero.thtd_player_id and v:GetHealth() > 0 then
					count = count + 1
				end
			end
			
			hero.thtd_game_info["creep_count"] = count
			if count == hero.thtd_game_info["creep_count_max"] and GameRules.player_bb_buff[hero.thtd_player_id]["item_3019"] > 0 and GameRules.player_bb_buff[hero.thtd_player_id]["item_3019_enable"] == false and SpawnSystem.CurWave > 50 and SpawnSystem.CurTime <= 5 then
				GameRules.player_bb_buff[hero.thtd_player_id]["item_3019_enable"] = true
				hero:SetContextThink(DoUniqueString("modifier_bb_buff_3019"),
					function()
						GameRules.player_bb_buff[hero.thtd_player_id]["item_3019_enable"] = false
						return nil
					end,
				5.0)
			end
			if count > hero.thtd_game_info["creep_count_max"] then
				if hero.reimu_pet ~= nil and hero.reimu_pet.pet_level >= 2 then 
					for i=0,5 do
						local targetItem = hero.reimu_pet:GetItemInSlot(i)				
						if targetItem~=nil and targetItem:IsNull()==false and targetItem:GetAbilityName() == "item_2001" then
							hero.reimu_pet:CastAbilityNoTarget(targetItem, hero:GetPlayerOwnerID())
							hero.thtd_game_info["creep_count"] = 0
							break
						end
					end					
				end
				if hero.thtd_game_info["creep_count"] > 0 then						
					SpawnSystem:GameOver(hero)
					if SpawnSystem:GetCount() == 0 then return false end
				end
			end	
		end
	end

	return true
end

-- 指定玩家游戏结束
function SpawnSystem:GameOver(hero)
	if hero~=nil and hero:IsNull()==false and hero:IsAlive() and hero.is_game_over ~= true then
		RefreshItemListNetTable(hero)
		hero.is_game_over = true
		table.insert(SpawnSystem.GameOverPlayerId, hero.thtd_player_id)
				
		if hero.reimu_pet ~= nil then 
			if hero.reimu_pet.pet_tree ~= nil then 
				UTIL_Remove(hero.reimu_pet.pet_tree) 
			end
			UnitStunTarget(hero.reimu_pet,hero.reimu_pet,-1)
			hero.reimu_pet:SetAbsOrigin(Vector(0,0,0))
			hero.reimu_pet:AddNoDraw()
		end		
		UnitStunTarget(hero,hero,-1)	
		hero:THTD_DropItemAll()	
		hero:SetAbsOrigin(Vector(0,0,0))
		hero:AddNoDraw()
		THTD_EntitiesRectInner[hero.thtd_player_id] = {}

		local wave = SpawnSystem.CurWave
		local entities = Entities:FindAllByClassname("npc_dota_creature")
		local killed = false		
		for k,v in pairs(entities) do
			killed = false
			if SpawnSystem.IsUnLimited then 
				local findNum = string.find(v:GetUnitName(), 'creature_unlimited')				
				local findNum2 =  string.find(v:GetUnitName(), 'creature_bosses')
				if (findNum ~= nil or findNum2 ~= nil) and v~=nil and v:IsNull()==false and v:IsAlive() and v.thtd_player_index == hero.thtd_player_id then
					v.diseble_buff = true
					v:ForceKill(false)
					killed = true
				end
			else
				local findNum =  string.find(v:GetUnitName(), 'creature')
				if findNum ~= nil and v~=nil and v:IsNull()==false and v:IsAlive() and v.thtd_player_index == hero.thtd_player_id then
					v:ForceKill(false)
					killed = true
				end
			end

			if killed==false and SpawnSystem:GetCount() > 0 and v~=nil and v:IsNull()==false and v:IsAlive() and v:THTD_IsTower() and v:GetOwner() == hero then
				v:THTD_DropItemAll()							
				v:THTD_DestroyLevelEffect()						
				hero:AddItem(v.thtd_item)
				hero:THTD_DropItemAll()
				v:SetAbsOrigin(Vector(0,0,0))
				v:AddNoDraw() 
				v:AddNewModifier(hero, nil, "modifier_touhoutd_release_hidden", {})	
				for _,u in pairs(entities) do
					if u~=nil and u:IsNull()==false and u:IsAlive() and u.thtd_spawn_unit_owner~=nil and u.thtd_spawn_unit_owner==v then 
						u:AddNoDraw()
						u:ForceKill(false)
					end
				end
			end
		end				
		
		-- 过挑战第一波BOSS算上榜
		if wave > 100 then
			CheckRank(hero)
			CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="power_game_end_info", duration=60, params={wave=hero.thtd_game_info["max_wave"],name=PlayerResource:GetPlayerName(hero:GetPlayerID())}, color="#ff0"})
			ShowDetail(hero)
		elseif wave > 50 then 
			CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="normal_game_end_info", duration=30, params={wave=wave-51,name=PlayerResource:GetPlayerName(hero:GetPlayerID())}, color="#f00"})
		end
		SpawnSystem:RefreshCreepMaxCount()	
	end

	if SpawnSystem:GetCount() == 0 then
		SpawnSystem:GameEnd()					
	end
end

-- 全部游戏结束
function SpawnSystem:GameEnd()
	local difficulty = GameRules:GetCustomGameDifficulty()
	local wave = SpawnSystem.CurWave

	if difficulty < UNLIMITED_MODE and wave > 100 then 	
		GameRules:GetGameModeEntity():SetContextThink(DoUniqueString("thtd_end_game"), 
			function()
				GameRules:SetGameWinner(DOTA_TEAM_GOODGUYS)
				return nil
			end,
		1)		
		return
	end

	if wave > 100 then
		CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="game_will_end", duration=60, params={}, color="#ff0"})
		GameRules:GetGameModeEntity():SetContextThink(DoUniqueString("thtd_end_game"), 
			function()
				GameRules:SetGameWinner(DOTA_TEAM_GOODGUYS)
				return nil
			end,
		60)					
	else
		GameRules:GetGameModeEntity():SetContextThink(DoUniqueString("thtd_end_game"), 
			function()
				Entities:FindByName(nil, "dota_goodguys_fort"):ForceKill(false)
				return nil
			end,
		1)	
	end
end

-- 检查是否能上排行榜
function CheckRank(hero)	
	if GameRules.players_rank_ok ~= true then return end
	if hero.thtd_game_info["max_wave"] == nil or hero.thtd_game_info["max_wave"] == 0 then return end
	if hero.cards == nil then return end

	local RANK_COUNT = 50 --排行榜排名人数

	local playerid = hero:GetPlayerOwnerID()
	local steamid = tostring(PlayerResource:GetSteamID(playerid))

	local wavedata = {}		
	wavedata["wave"] = hero.thtd_game_info["max_wave"]
	wavedata["damage"] = hero.thtd_game_info["max_wave_damage"] / 10000	
	for i=0,12 do
		if (i+1) <= #hero.cards then 
			wavedata["card"..tostring(i)] = hero.cards[i+1]
		else
			wavedata["card"..tostring(i)] = ""
		end
	end

	-- 确定上传的排行榜
	local isTeamMode = hero.is_team_mode	
	if not isTeamMode then 	
		for i=1,3 do
			if wavedata["card"..tostring(i)] ~= nil and wavedata["card"..tostring(i)]["itemname"] ~= nil and (towerNameList[wavedata["card"..tostring(i)]["itemname"]]["cardname"] == GameRules.GameData.luck_card or GameRules.GameData.luck_card == "all") then 
				isTeamMode = true    
				hero.is_team_mode = true
				break  
			end
		end		
	end

	if isTeamMode then 		
		if wavedata["wave"] <= GameRules.PlayerData[playerid].max_team_wave then return end
		if #GameRules.players_team_rank >= RANK_COUNT and wavedata["wave"] <= GameRules.players_team_rank[RANK_COUNT].wave then return end		
	else		
		if wavedata["wave"] <= GameRules.PlayerData[playerid].max_wave then return end
		if #GameRules.players_rank >= RANK_COUNT and wavedata["wave"] <= GameRules.players_rank[RANK_COUNT].wave then return end
	end	
	
	local toplist
	if isTeamMode then
		toplist = GameRules.players_team_rank_data	
	else
		toplist = GameRules.players_rank_data
	end

	local toDelList = {}
	local isTop = true
	local rankIndex = 0 --排名	
	local bestWave = 0	

	if #toplist > 0 then
		for i=1,#toplist do
			local topdata = toplist[i]
			if rankIndex == 0 and wavedata["wave"] > topdata["wave"] then
				rankIndex = i
			end

			if steamid ~= topdata["steamid"] then
				local isSameRank = false 

				if wavedata["card1"] ~= "" and topdata["card1"] ~= "" and topdata["card1"] ~= nil and wavedata["card1"]["itemname"] == topdata["card1"]["itemname"] then
					if wavedata["card1"]["damage"] / (10000 * wavedata["damage"]) >= 0.6 and topdata["card1"]["damage"] / (10000 * topdata["damage"]) >= 0.6 then
						isSameRank = true
					end						
				end				

				if isSameRank ~= true then
					local topDamage1 = 0
					local topDamage2 = 0
					local topNum = 0
					for x=1,12 do
						if wavedata["card"..tostring(x)] ~= "" then
							topDamage1 = topDamage1 + wavedata["card"..tostring(x)]["damage"]
						end
						if topdata["card"..tostring(x)] ~= "" and topdata["card"..tostring(x)] ~= nil then
							topDamage2 = topDamage2 + topdata["card"..tostring(x)]["damage"]
						end						
						if topDamage1 / (10000 * wavedata["damage"]) >= 0.8 and topDamage2 / (10000 * topdata["damage"]) >= 0.8 then
							topNum = x
							break
						end					
					end
					if topNum > 0 then
						local usedIndex = ""
						local sameCount = 0
						for x=1,topNum do
							for y=1,topNum do
								if string.find(usedIndex,tostring(y)) == nil and wavedata["card"..tostring(x)] ~= "" and topdata["card"..tostring(y)] ~= "" and topdata["card"..tostring(y)] ~= nil and wavedata["card"..tostring(x)]["itemname"] == topdata["card"..tostring(y)]["itemname"] then
									sameCount = sameCount + 1
									usedIndex = usedIndex..tostring(y)..","
									break
								end					
							end
						end	
						if sameCount == topNum then isSameRank = true end
					end
				end

				if isSameRank == true then
					if wavedata["wave"] <= topdata["wave"] then
						if isTop ~= false then isTop = false end
						if bestWave == 0 then bestWave = topdata["wave"] end
					else
						table.insert(toDelList, i)				
					end				
				end			
			end
		end
	end	
	
	for k,v in pairs(toDelList) do
		if isTeamMode then
			Service:ResetRank(v,"D")
		else
			Service:ResetRank(v,"S")			
		end
	end
	GameRules:SendCustomMessage("<font color='blue'>clear the same rank : "..json.encode(toDelList).."</font>", DOTA_TEAM_GOODGUYS, 0)

	if not isTop then
		CustomGameEventManager:Send_ServerToPlayer(hero:GetPlayerOwner(), "thtd_server_msg", {code = "0000", msg = "你打破了自己的历史记录，但没有超过该阵容的最高波数 "..bestWave.."，请再接再厉!", duration = 30})				
		return	
	end

	if rankIndex == 0 then rankIndex = #toplist + 1 end
	wavedata["rank_index"] = rankIndex	
	
	if isTeamMode then 
		Service:UploadRank(playerid, "D", wavedata)
	else 
		Service:UploadRank(playerid, "S", wavedata)
	end
end

-- 显示最大波数信息
function ShowDetail(hero)
	if hero.cards == nil or #hero.cards == 0 then return end
	
	local wavedata = {}	
	for i=0,12 do
		if (i+1) <= #hero.cards then 
			wavedata["card"..tostring(i)] = hero.cards[i+1]
		else
			wavedata["card"..tostring(i)] = ""
		end
	end	
	wavedata['wave'] = hero.thtd_game_info["max_wave"]

	CustomGameEventManager:Send_ServerToPlayer(hero:GetPlayerOwner(), "thtd_game_over_detail", wavedata)	
end

-- 检查玩家是否掉线
function CheckPlayerConnect()
	local spawner = SpawnSystem.AttackingSpawner	
	if spawner == nil or #spawner == 0 then return end		
	for spawnerIndex,spawnerLine in pairs(spawner) do	
		local hero = spawnerLine.hero
		if (hero:GetPlayerOwner() == nil or hero:GetPlayerOwner():IsNull()) then
			if hero.thtd_game_info["is_player_connected"] then 
				hero.thtd_game_info["is_player_connected"] = false
				CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="player_disconnect", duration=15, params={count=1}, color="#0ff"} )
				CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="{d:count}", duration=15, params={count=hero.thtd_player_id+1}, color="#ff0"})			
				CustomGameEventManager:Send_ServerToAllClients("show_message", {msg="pause_game", duration=15, params={}, color="#ff0"})
				if GameRules:IsGamePaused() then PauseGame(false) end
				PauseGame(true)
			end
		else
			if not hero.thtd_game_info["is_player_connected"] then hero.thtd_game_info["is_player_connected"] = true end			
		end	
	end
end

-- 每波刷怪结束各线路数据更新，伤害清零，统计更新
function SpawnSystem:WaveEndForEach()
	local spawner = SpawnSystem.AttackingSpawner	
	if spawner == nil or #spawner == 0 then return end	
	local wave = SpawnSystem.CurWave
	local difficulty = GameRules:GetCustomGameDifficulty()
	for spawnerIndex,spawnerLine in pairs(spawner) do
		local hero = spawnerLine.hero    
		if hero.is_game_over ~= true then
			local isMaxWave = false	
			if wave >= SpawnSystem.RankMinWave then 											
				local totalDamage = 0					
				for k,v in pairs(hero.thtd_hero_tower_list) do
					if v~=nil and v:IsNull()==false then
						totalDamage = totalDamage + v:THTD_GetTowerDamage()
					end
				end
				if totalDamage < hero.thtd_wave_total_health * 0.9 then		
					CustomGameEventManager:Send_ServerToPlayer(hero:GetPlayerOwner(), "display_chat_msg", {msg="damage_less_rank_tip", params={player_name=PlayerResource:GetPlayerName(hero:GetPlayerOwnerID())}})
				else
					isMaxWave = true 	
				end						
			end	
			-- todo test	
			-- isMaxWave = true			
			if isMaxWave then
				hero.thtd_game_info["max_wave"] = wave - 50
				hero.thtd_game_info["max_wave_damage"] = 0
				hero.cards = {}					
			end

			for k,v in pairs(hero.thtd_hero_tower_list) do		
				if v~=nil and v:IsNull()==false and v:IsAlive() then
					if isMaxWave then
						hero.thtd_game_info["max_wave_damage"] = hero.thtd_game_info["max_wave_damage"] + v:THTD_GetTowerDamage()/100						
						local card = {} 
						card["itemname"] = v.thtd_item:GetAbilityName()
						card["star"] = v:THTD_GetStar()
						card["damage"] = math.floor(v:THTD_GetTowerDamage()/100)
						card["power"] = math.floor(v:THTD_GetPower() or 0)
						card["attack"] = math.floor(v:THTD_GetAttack() or 0)
						card["equip"] = {}
						for i=0,5 do
							local targetItem = v:GetItemInSlot(i)
							if targetItem~=nil and targetItem:IsNull()==false then	
								table.insert(card["equip"], targetItem:GetAbilityName())
							end
						end
						if #card["equip"] == 0 then card["equip"] = nil end
						table.insert(hero.cards, card)
					end					
					if not SpawnSystem.IsUnLimited then
						if v:GetUnitName() == "toramaru" and GameRules:GetCustomGameDifficulty() < FUNNY_MODE then		
							local gold = math.floor(v:THTD_GetTowerDamage() * v:GetAbilityValue("thtd_toramaru_01", "gold_damage_percent"))
							THTD_ModifyGoldEx(v:GetPlayerOwnerID(),gold,true,DOTA_ModifyGold_CreepKill)
							SendOverheadEventMessage(v:GetPlayerOwner(),OVERHEAD_ALERT_GOLD,v,gold,v:GetPlayerOwner() )
						end						
					end
					v:THTD_ResetTowerDamage()
				end
			end
			hero.thtd_wave_total_health = 0

			if isMaxWave then
				hero.thtd_game_info["max_wave_damage"] = math.floor(hero.thtd_game_info["max_wave_damage"] + 0.5)
				table.sort(hero.cards, function(a,b) return a["damage"] > b["damage"] end) --坑：使用 a.damage >= b.damage 会失败

				local card = {} 
				card["itemname"] = "item_0028"
				card["star"] = 0
				card["damage"] = hero.next_boss_name or 0   -- 最后BOSS
				card["power"] = hero.use_item2001_count or 0   --爆弹数量 
				card["attack"] = 0   --核心数,js计算
				card["equip"] = hero.bb_buff or {}	
				if #card["equip"] == 0 then
					for i=0,5 do
						local targetItem = hero:GetItemInSlot(i)
						if targetItem~=nil and targetItem:IsNull()==false then	
							table.insert(card["equip"], targetItem:GetAbilityName())
						end
					end
				end
				if #card["equip"] == 0 then card["equip"] = nil end
				table.insert(hero.cards, 1, card)
			end	

			-- 清空空值
			local inner = THTD_EntitiesRectInner[hero.thtd_player_id]
			if inner ~= nil then
				for i = #inner, 1, -1 do
					if inner[i]==nil or inner[i]:IsNull() or inner[i]:IsAlive()==false then 
						table.remove(inner, i)	
					end
				end
			end

			if SpawnSystem.IsUnLimited == false and wave >= 30 and wave < 50 and GameRules:GetCustomGameDifficulty() >= FUNNY_MODE then
				for i=1,4 do					
					local item = CreateItem("item_1006", nil, nil)
					item.owner_player_id = hero.thtd_player_id
					item:SetPurchaser(hero)
					item:SetPurchaseTime(1.0)
					local pos = GetSpawnLineOffsetVector(hero.spawn_index, hero.spawn_position, (i-1) * 130, 150)					
					CreateItemOnPositionSync(pos, item)
				end	
			end

			-- 战利品奖励关
			SpawnSystem:OnBattleBonusWave(hero)

			-- 战斗中铸就
			if wave > 50 and wave < 1050 and GameRules.player_bb_buff[hero.thtd_player_id]["item_3014"] > 0 then
				local bonusTargets = {}
				for k,v in pairs(hero.thtd_hero_tower_list) do
					local unitName = v:GetUnitName()
					if unitName == "reimu" or unitName == "marisa" or unitName == "sanae" or unitName == "alice" then
						table.insert(bonusTargets, v)
					end
				end	
				if #bonusTargets > 0 then
					local bonusWave = SpawnSystem.CurWave - (hero.bb_buff3014_last_wave or 50)
					hero.bb_buff3014_last_wave = SpawnSystem.CurWave
					local bonusPower = GameRules.player_bb_buff[hero.thtd_player_id]["item_3014"] * bonusWave
					for k,v in pairs(bonusTargets) do
						v:THTD_AddBasePower(bonusPower)
					end
					bonusTargets = {}
				end				
			end

			-- 封兽鵺跳关扣减层数
			if SpawnSystem.ReachToWave ~= nil then 
				local deCount = math.max(0, SpawnSystem.ReachToWave + 50 - wave) * 20
				if deCount > 0 then 
					for k,v in pairs(hero.thtd_hero_tower_list) do
						local unitName = v:GetUnitName()
						if unitName == "nue" then
							local modifier = v:FindModifierByName("modifier_nue_01_extradamage")
							if modifier ~= nil then 
								modifier:SetStackCount(math.max(1, modifier:GetStackCount() - deCount))
							end
						end
					end	
				end
			end

		end
	end

	-- 清空空值
	if THTD_EntitiesRectOuter ~= nil then 
		for i = #THTD_EntitiesRectOuter, 1, -1 do
			if THTD_EntitiesRectOuter[i]==nil or THTD_EntitiesRectOuter[i]:IsNull() or THTD_EntitiesRectOuter[i]:IsAlive()==false then 
				table.remove(THTD_EntitiesRectOuter, i)	
			end
		end
	end
end

-- 代替触发器
local UnitMoveRect = {
	[0] = {
		[1] = {			
			["center"] = {-2200, 1550},
			["radius"] = 200,
			["tag"] = {2}
		},
		[2] = {		
			["center"] = {-4100, 1600},
			["radius"] = 100,					
			["tag"] = {3}
		},
		[3] = {			
			["center"] = {-4100, 4120},
			["radius"] = 100,		
			["tag"] = {4, 7}
		},
		[4] = {			
			["center"] = {6750, 4120},
			["radius"] = 100,		
			["tag"] = {5, 7}
		},
		[5] = {			
			["center"] = {6750, -4120},
			["radius"] = 100,		
			["tag"] = {4, 6}
		},
		[6] = {			
			["center"] = {-6750, -4120},
			["radius"] = 100,		
			["tag"] = {5, 7}
		},
		[7] = {			
			["center"] = {-6750, 4120},
			["radius"] = 100,		
			["tag"] = {4, 6}
		},
	}, 
	[1] = {
		[1] = {			
			["center"] = {2200, 1550},
			["radius"] = 200,
			["tag"] = {2 }
		},
		[2] = {		
			["center"] = {4100, 1600},
			["radius"] = 100,					
			["tag"] = {3 }
		},
		[3] = {			
			["center"] = {4100, 4120},
			["radius"] = 100,		
			["tag"] = {4, 7}
		},
		[4] = {			
			["center"] = {6750, 4120},
			["radius"] = 100,		
			["tag"] = {5, 7}
		},
		[5] = {			
			["center"] = {6750, -4120},
			["radius"] = 100,		
			["tag"] = {4, 6}
		},
		[6] = {			
			["center"] = {-6750, -4120},
			["radius"] = 100,		
			["tag"] = {5, 7}
		},
		[7] = {			
			["center"] = {-6750, 4120},
			["radius"] = 100,		
			["tag"] = {4, 6}
		},
	}, 
	[2] = {
		[1] = {			
			["center"] = {2200, -1550},
			["radius"] = 200,
			["tag"] = {2 }
		},
		[2] = {		
			["center"] = {4100, -1600},
			["radius"] = 100,					
			["tag"] = {3 }
		},
		[3] = {			
			["center"] = {4100, -4120},
			["radius"] = 100,		
			["tag"] = {5, 6}
		},
		[4] = {			
			["center"] = {6750, 4120},
			["radius"] = 100,		
			["tag"] = {5, 7}
		},
		[5] = {			
			["center"] = {6750, -4120},
			["radius"] = 100,		
			["tag"] = {4, 6}
		},
		[6] = {			
			["center"] = {-6750, -4120},
			["radius"] = 100,		
			["tag"] = {5, 7}
		},
		[7] = {			
			["center"] = {-6750, 4120},
			["radius"] = 100,		
			["tag"] = {4, 6}
		},
	}, 
	[3] = {
		[1] = {			
			["center"] = {-2200, -1550},
			["radius"] = 200,
			["tag"] = {2 }
		},
		[2] = {		
			["center"] = {-4100, -1600},
			["radius"] = 100,					
			["tag"] = {3 }
		},
		[3] = {			
			["center"] = {-4100, -4120},
			["radius"] = 100,		
			["tag"] = {5, 6}
		},
		[4] = {			
			["center"] = {6750, 4120},
			["radius"] = 100,		
			["tag"] = {5, 7}
		},
		[5] = {			
			["center"] = {6750, -4120},
			["radius"] = 100,		
			["tag"] = {4, 6}
		},
		[6] = {			
			["center"] = {-6750, -4120},
			["radius"] = 100,		
			["tag"] = {5, 7}
		},
		[7] = {			
			["center"] = {-6750, 4120},
			["radius"] = 100,		
			["tag"] = {4, 6}
		},
	}	
}

-- 代替触发器
local UnitMoveRectAll = {
	[1] = {			
		["center"] = {-2200, 1550},
		["radius"] = 200,
		["tag"] = {
			["left"] = {
				{
					["forward"] = "left",
					["index"] = 2
				},
			}, 
		}
	},
	[2] = {		
		["center"] = {-4100, 1600},
		["radius"] = 100,					
		["tag"] = {
			["left"] = {
				{
					["forward"] = "up",
					["index"] = 3
				},
			}, 
		}
	},
	[3] = {			
		["center"] = {-4100, 4120},
		["radius"] = 100,	
		["tag"] = {
			["up"] = {
				{
					["forward"] = "left",
					["index"] = 4
				},
				{
					["forward"] = "right",
					["index"] = 5
				},
			}, 
		}				
	},
	[4] = {			
		["center"] = {-6750, 4120},
		["radius"] = 100,		
		["tag"] = { }
	},
	[5] = {			
		["center"] = {10, 4120},
		["radius"] = 100,		
		["tag"] = { }
	},	
}

-- 随机BOSS自带buff
local RandomBossBuff = {
	"modifier_bosses_random_aura_dark",
	"modifier_bosses_random_attack_speed_aura",
	"modifier_bosses_random_move_aura",
	"modifier_bosses_random_health_aura",
	"modifier_bosses_random_dead_heal"
}

-- 解决草地问题
local UnitPathFixRect = {
	[0] = {
		[0] = {		-- 靠商店侧	
			[1] = Vector(-3600, 1800, 128), --左下角
			[2] = Vector(-2100, 2600, 128), --右上角			
		},
		[1] = {		-- 靠商店侧	
			[1] = Vector(-2100, 1700, 128), --左下角
			[2] = Vector(-1020, 2600, 128), --右上角			
		},
		[2] = {		-- 拐角
			[1] = Vector(-1900, 1420, 128), --靠内上角
			[2] = Vector(-2700, 100, 128),  --靠外下角
		},		
	},
	[1] = {
		[0] = {		-- 靠商店侧	
			[1] = Vector(2100, 1800, 128), --左下角
			[2] = Vector(3600, 2600, 128), --右上角			
		},
		[1] = {		-- 靠商店侧	
			[1] = Vector(1020, 1700, 128), 
			[2] = Vector(2100, 2600, 128), 
		},
		[2] = {		-- 拐角
			[1] = Vector(1900, 1420, 128), 
			[2] = Vector(2700, 100, 128), 
		},		
	}, 
	[2] = {
		[0] = {		-- 靠商店侧	
			[1] = Vector(2100, -2600, 128), --左下角
			[2] = Vector(3600, -1800, 128), --右上角			
		},
		[1] = {		-- 靠商店侧	
			[1] = Vector(1020, -2600, 128), 
			[2] = Vector(2100, -1700, 128), 		
		},
		[2] = {		-- 拐角
			[1] = Vector(1900, -1420, 128), 
			[2] = Vector(2700, -100, 128), 
		},		
	}, 
	[3] = {
		[0] = {		-- 靠商店侧	
			[1] = Vector(-3600, -2600, 128), --左下角
			[2] = Vector(-2100, -1800, 128), --右上角			
		},
		[1] = {		-- 靠商店侧	
			[1] = Vector(-2100, -2600, 128), 
			[2] = Vector(-1020, -1700, 128), 	
		},
		[2] = {		-- 拐角
			[1] = Vector(-1900, -1420, 128), 
			[2] = Vector(-2700, -100, 128), 
		},		
	}	
}

-- 刷怪
function SpawnSystem:StartSpawn()	
	local spawner = SpawnSystem.AttackingSpawner	
	if spawner == nil or #spawner == 0 then return end	
	local difficulty = GameRules:GetCustomGameDifficulty()

	local wave = SpawnSystem.CurWave
	local waveInfo = nil
	if wave <= 51 then
		waveInfo = SpawnSystem.Spawner["Attacking"]["Wave"..tostring(wave)]
	else
		waveInfo = SpawnSystem.Spawner["Attacking"]["Wave51"]
	end

	local count = waveInfo["Count"]
	local times = waveInfo["Times"]
	local interval = waveInfo["Interval"]	
	
	for spawnerIndex,spawnerLine in pairs(spawner) do
		local hero = spawnerLine.hero    
		if hero.is_game_over ~= true then 
			local player = hero:GetPlayerOwner()
			local playerId = hero:GetPlayerOwnerID()
			-- 刷新BOSS信息并重置秋
			if difficulty >= EXTRA_MODE then
				if wave > 50 and wave%4 == 3 then									
					hero.thtd_minoriko_02_change = 0
					THTD_ModifyGoldEx(playerId,3500,true,DOTA_ModifyGold_CreepKill)
					for k,v in pairs(hero.thtd_hero_tower_list) do
						if v~=nil and v:IsNull()==false and v:IsAlive() then
							if v:THTD_IsTower() and v:THTD_GetLevel()<THTD_MAX_LEVEL then
								v:THTD_SetLevel(THTD_MAX_LEVEL)
							end
						end
					end
					spawnerLine.nextBossName = thtd_bosses_list[RandomInt(1, #thtd_bosses_list)]
					hero.next_boss_name = spawnerLine.nextBossName
					if player ~= nil then 
						CustomGameEventManager:Send_ServerToPlayer(player,"show_message", {msg="extra_bonus_nazrin", duration=60, params={count=1}, color="#0ff"} )
						CustomGameEventManager:Send_ServerToPlayer(player,"show_message", {msg="extra_bonus_minoriko_limit", duration=60, params={count=1}, color="#0ff"} )
						CustomGameEventManager:Send_ServerToPlayer(player,"show_message", {msg="extra_bonus_lily", duration=60, params={count=1}, color="#0ff"} )
						CustomGameEventManager:Send_ServerToPlayer(player,"show_message", {msg="extra_bosses_"..spawnerLine.nextBossName, duration=60, params={count=1}, color="#0ff"} )	
					end		
				end
			end

			local curTimes = 1
			local randomBossIndex = RandomInt(1, times-10)			
			spawnerLine:SetContextThink(DoUniqueString("SpawnAttackingSpawn"..tostring(spawnerIndex)), 
				function()
					if GameRules:IsGamePaused() then return 0.1 end
					if curTimes > times  then return nil end					

					for i = 1, count do
						if hero.is_game_over == true then return nil end
		
						local spawn_unit = waveInfo["Unit"]
						
						if difficulty >= EXTRA_MODE and wave > 50 and wave%4 == 0 and spawnerLine.nextBossName ~= nil then
							spawn_unit = "creature_bosses_"..spawnerLine.nextBossName
						end
								
						local unit = CreateUnitByName(spawn_unit, spawnerLine:GetOrigin() + RandomVector(400), true, nil, nil, DOTA_TEAM_BADGUYS )
						if unit ~= nil then 
							unit.thtd_player_index = hero.thtd_player_id
							
							unit.thtd_damage_incoming_magical_percentage = 0
							unit.thtd_damage_incoming_physical_percentage = 0
							unit.thtd_damage_incoming_pure_percentage = 0
							unit.thtd_damage_block_pure = 0
							unit.thtd_damage_block_physical = 0
							unit.thtd_damage_block_magical = 0
			
							unit:AddNewModifier(unit, nil, "modifier_phased", {})
										
							if wave > 50 then								
								local health = math.min(MAX_HEALTH, unit:GetBaseMaxHealth() * SpawnSystem:GetWaveHpFactor())
								unit:SetBaseMaxHealth(health)
								unit:SetMaxHealth(health)
								unit:SetHealth(health)									
								
								if difficulty >= EXTRA_MODE then 
									if wave%4 == 0 and spawnerLine.nextBossName ~= nil then
										unit:AddNewModifier(unit, nil, "modifier_bosses_"..spawnerLine.nextBossName, nil)
									elseif wave%4 ~= 0 and curTimes == randomBossIndex then
										unit.is_random_boss = true
										health = math.min(MAX_HEALTH, health * 1.5)
										unit:SetBaseMaxHealth(health)
										unit:SetMaxHealth(health)
										unit:SetHealth(health)
										unit:SetModelScale(unit:GetModelScale() * 1.5)
										
										-- 随机Buff	
										local bossBuffChance = 25
										if wave >= 200 then 
											bossBuffChance = 100
										elseif wave >= 150 then 
											bossBuffChance = 75
										elseif wave >= 100 then 
											bossBuffChance = 50
										end
										if RollPercentage(bossBuffChance) then
											local modifierName = RandomBossBuff[RandomInt(1, #RandomBossBuff)]
											unit:AddNewModifier(unit, nil, modifierName, {})
											if player ~= nil then 
												CustomGameEventManager:Send_ServerToPlayer(player,"show_message", {msg="random_boss_has_buff", duration=20, params={}, color="#0ff"})
												CustomGameEventManager:Send_ServerToPlayer(player,"show_message", {msg="DOTA_Tooltip_"..modifierName.."_Description", duration=20, params={}, color="#0ff"})
											end
										end							
									end	
								end															

								if GameRules.player_bb_buff[hero.thtd_player_id]["item_3026"] > 0 then
									local modifier = unit:AddNewModifier(unit, nil, "modifier_move_speed", nil)
									modifier:SetStackCount(800+GameRules.player_bb_buff[hero.thtd_player_id]["item_3026"])
								end

								-- 少女之抵抗
								if wave >= 50 + 250 + 30 then
									local unlimitedResist = 0
									if wave <= 50 + 3220 then
										unlimitedResist = math.floor((wave - 50 - 250)/30)
									else --max: 无尽5218
										unlimitedResist = 99 + math.min(0.999, 0.001 * math.floor((wave - 50 - 3220) / 2))
									end
									local modifier = unit:AddNewModifier(unit, nil, "modifier_touhoutd_unlimited_resist", {})
									if modifier ~= nil then 
										modifier:SetStackCount(math.floor(unlimitedResist))
									end		
									unit.unlimited_resist = unlimitedResist					
								end

								hero.thtd_wave_total_health = hero.thtd_wave_total_health + health/100								
							else
								local modifier = unit:AddNewModifier(unit, nil, "modifier_move_speed", nil)
								if modifier ~= nil then 
									modifier:SetStackCount(math.floor(wave/4)*20)
								end
								if difficulty == NORMAL_MODE then 
									unit:AddDamageIncomingAll(30)									
								end														
							end					
										
							table.insert(THTD_EntitiesRectInner[hero.thtd_player_id], unit)
												
							unit.thtd_first_corner = spawnerLine.first_point
							unit.first_move_forward = spawnerLine.first_forward 
							unit.first_move_point = G_path_corner[unit.thtd_first_corner].Vector * 1.5

							unit.thtd_second_corner = spawnerLine.second_point
							unit.second_move_forward = spawnerLine.second_forward 
							unit.second_move_point = G_path_corner[unit.thtd_second_corner].Vector * 1.5					

							unit.thtd_next_corner = unit.thtd_first_corner
							unit.next_move_forward = unit.first_move_forward
							unit.next_move_point = unit.first_move_point
			
							unit:SetContextThink(DoUniqueString("AttackingBase"), 
								function ()
									if GameRules:IsGamePaused() then return 0.1 end
									if unit == nil or unit:IsNull() or unit:IsAlive() == false then return nil end
			
									local origin = unit:GetOrigin()
									if unit.thtd_is_outer ~= true then										
										if not(origin.x < 4432 and origin.x > -4432 and origin.y < 3896 and origin.y > -3896) then
											unit.thtd_is_outer = true
											table.insert(THTD_EntitiesRectOuter,unit)
											for k,v in pairs(THTD_EntitiesRectInner[hero.thtd_player_id]) do
												if v == unit then										
													table.remove(THTD_EntitiesRectInner[hero.thtd_player_id],k)
													break
												end
											end
										end

										-- 修正卡怪问题
										if unit.thtd_is_fearing ~= true then 
											if math.abs(origin.x) < math.abs(unit.first_move_point.x) - 150 then
												if unit.next_move_point ~= unit.first_move_point then 
													unit.thtd_next_corner = unit.thtd_first_corner
													unit.next_move_forward = unit.first_move_forward
													unit.next_move_point = unit.first_move_point
												end												
											else
												if math.abs(origin.x) < math.abs(unit.second_move_point.x) - 300 and unit.next_move_point ~= unit.second_move_point then 
													unit.thtd_next_corner = unit.thtd_second_corner
													unit.next_move_forward = unit.second_move_forward
													unit.next_move_point = unit.second_move_point		
												end										
											end
										end
									end
									unit:MoveToPosition(unit.next_move_point)
									
									-- 草地路径修正									
									if 
										origin.x > UnitPathFixRect[unit.thtd_player_index][0][1].x and 
										origin.x < UnitPathFixRect[unit.thtd_player_index][0][2].x and 
										origin.y > UnitPathFixRect[unit.thtd_player_index][0][1].y and 
										origin.y < UnitPathFixRect[unit.thtd_player_index][0][2].y then
										if unit.thtd_player_index <= 1 then
											unit:SetAbsOrigin(Vector(origin.x, UnitPathFixRect[unit.thtd_player_index][0][1].y - 5, UnitPathFixRect[unit.thtd_player_index][0][1].z))
										else
											unit:SetAbsOrigin(Vector(origin.x, UnitPathFixRect[unit.thtd_player_index][0][2].y + 10, UnitPathFixRect[unit.thtd_player_index][0][2].z))
										end
									elseif 
										origin.x > UnitPathFixRect[unit.thtd_player_index][1][1].x and 
										origin.x < UnitPathFixRect[unit.thtd_player_index][1][2].x and 
										origin.y > UnitPathFixRect[unit.thtd_player_index][1][1].y and 
										origin.y < UnitPathFixRect[unit.thtd_player_index][1][2].y then
										if unit.thtd_player_index <= 1 then
											unit:SetAbsOrigin(Vector(origin.x, UnitPathFixRect[unit.thtd_player_index][1][1].y - 5, UnitPathFixRect[unit.thtd_player_index][1][1].z))
										else
											unit:SetAbsOrigin(Vector(origin.x, UnitPathFixRect[unit.thtd_player_index][1][2].y + 7, UnitPathFixRect[unit.thtd_player_index][1][2].z))
										end
									elseif unit.thtd_player_index == 0 then
										if origin.x > UnitPathFixRect[unit.thtd_player_index][2][2].x and 
											origin.x < UnitPathFixRect[unit.thtd_player_index][2][1].x and 
											origin.y > UnitPathFixRect[unit.thtd_player_index][2][2].y and 
											origin.y < UnitPathFixRect[unit.thtd_player_index][2][1].y then
												if math.abs(origin.x - UnitPathFixRect[unit.thtd_player_index][2][1].x) > math.abs(origin.y - UnitPathFixRect[unit.thtd_player_index][2][1].y) then
													unit:SetAbsOrigin(Vector(origin.x, UnitPathFixRect[unit.thtd_player_index][2][1].y + 10, UnitPathFixRect[unit.thtd_player_index][2][2].z))
												else --y增量要大于移速，防止已切换移动到第二个点拉回来卡住
													unit:SetAbsOrigin(Vector(UnitPathFixRect[unit.thtd_player_index][2][1].x + 5, origin.y + 100, UnitPathFixRect[unit.thtd_player_index][1][1].z))
												end
										end
									elseif unit.thtd_player_index == 1 then
										if origin.x > UnitPathFixRect[unit.thtd_player_index][2][1].x and 
											origin.x < UnitPathFixRect[unit.thtd_player_index][2][2].x and 
											origin.y > UnitPathFixRect[unit.thtd_player_index][2][2].y and 
											origin.y < UnitPathFixRect[unit.thtd_player_index][2][1].y then
												if math.abs(origin.x - UnitPathFixRect[unit.thtd_player_index][2][1].x) > math.abs(origin.y - UnitPathFixRect[unit.thtd_player_index][2][1].y) then
													unit:SetAbsOrigin(Vector(origin.x, UnitPathFixRect[unit.thtd_player_index][2][1].y + 5, UnitPathFixRect[unit.thtd_player_index][2][2].z))
												else
													unit:SetAbsOrigin(Vector(UnitPathFixRect[unit.thtd_player_index][2][1].x - 5, origin.y + 100, UnitPathFixRect[unit.thtd_player_index][1][1].z))
												end
										end
									elseif unit.thtd_player_index == 2 then
										if origin.x > UnitPathFixRect[unit.thtd_player_index][2][1].x and 
											origin.x < UnitPathFixRect[unit.thtd_player_index][2][2].x and 
											origin.y > UnitPathFixRect[unit.thtd_player_index][2][1].y and 
											origin.y < UnitPathFixRect[unit.thtd_player_index][2][2].y then
												if math.abs(origin.x - UnitPathFixRect[unit.thtd_player_index][2][1].x) > math.abs(origin.y - UnitPathFixRect[unit.thtd_player_index][2][1].y) then
													unit:SetAbsOrigin(Vector(origin.x, UnitPathFixRect[unit.thtd_player_index][2][1].y - 5, UnitPathFixRect[unit.thtd_player_index][2][2].z))
												else
													unit:SetAbsOrigin(Vector(UnitPathFixRect[unit.thtd_player_index][2][1].x - 5, origin.y - 100, UnitPathFixRect[unit.thtd_player_index][1][1].z))
												end
										end				
									elseif unit.thtd_player_index == 3 then
										if origin.x > UnitPathFixRect[unit.thtd_player_index][2][2].x and 
											origin.x < UnitPathFixRect[unit.thtd_player_index][2][1].x and 
											origin.y > UnitPathFixRect[unit.thtd_player_index][2][1].y and 
											origin.y < UnitPathFixRect[unit.thtd_player_index][2][2].y then
												if math.abs(origin.x - UnitPathFixRect[unit.thtd_player_index][2][1].x) > math.abs(origin.y - UnitPathFixRect[unit.thtd_player_index][2][1].y) then
													unit:SetAbsOrigin(Vector(origin.x, UnitPathFixRect[unit.thtd_player_index][2][1].y - 5, UnitPathFixRect[unit.thtd_player_index][2][2].z))
												else
													unit:SetAbsOrigin(Vector(UnitPathFixRect[unit.thtd_player_index][2][1].x + 5, origin.y - 100, UnitPathFixRect[unit.thtd_player_index][1][1].z))
												end
										end							
									end
									
									-- 替代触发器
									-- for k,v in pairs(UnitMoveRect[unit.thtd_player_index]) do
									-- 	if GetDistanceBetweenTwoVec2D(unit:GetOrigin(), Vector(v["center"][1],v["center"][2]),0) <= v["radius"] then 
									-- 		if unit.current_rect_id ~= k then 
									-- 			unit.current_rect_id = k
									-- 			local tagIndex = v["tag"][RandomInt(1, #v["tag"])]
									-- 			unit.next_move_point = Vector(UnitMoveRect[unit.thtd_player_index][tagIndex]["center"][1],UnitMoveRect[unit.thtd_player_index][tagIndex]["center"][2],0)
									-- 			unit:MoveToPosition(unit.next_move_point)
									-- 		end
									-- 		break
									-- 	end								
									-- end

									UnitDamageApply(unit)

									return 0.15
								end, 
							0) 
						end
					end
		
					curTimes = curTimes + 1		
					return interval					
				end, 
			0)
		end
	end	
end


-- 刷新宝箱
local chest_list = {
	[1] = {
		["chest"] = nil, 
		["pos"] = Vector(-2245, 2866, 0)
	},
	[2] = {
		["chest"] = nil, 
		["pos"] = Vector(2320, 3176, 0)
	},
	[3] = {
		["chest"] = nil, 
		["pos"] = Vector(2360, -2607, 0)
	},
	[4] = {
		["chest"] = nil, 
		["pos"] = Vector(-2230, -3013, 0)
	},
}
function SpawnSystem:SpawnChest()	
	for i=1,#SpawnSystem.AttackingSpawner do		
		if IsValidEntity(chest_list[i]["chest"]) == false then
			local item = CreateItem("item_310"..tostring(RandomInt(1, 3)), nil, nil)			
			if item ~= nil then
				local drop = CreateItemOnPositionSync(Vector(0, 0, 0), item)
				if drop ~= nil then 
					drop:SetModelScale(drop:GetModelScale() * 2)
					item:LaunchLoot(false, 600, 0.75, chest_list[i]["pos"])
					chest_list[i]["chest"] = item					
				end
			end
		end
	end	
end

-- 无尽生命成长倍数，addWave为取前后多少波（负前正后），默认为当前波
function SpawnSystem:GetWaveHpFactor()
	local wave = SpawnSystem.CurWave - 50

	if wave > 250 then
		return (wave - 250) * 100 + 9700
	elseif wave > 240 then
		return (wave - 240) * 95 + 8750
	elseif wave > 230 then
		return (wave - 230) * 90 + 7850
	elseif wave > 220 then
		return (wave - 220) * 85 + 7000
	elseif wave > 210 then
		return (wave - 210) * 80 + 6200
	elseif wave > 200 then
		return (wave - 200) * 75 + 5450
	elseif wave > 190 then
		return (wave - 190) * 70 + 4750
	elseif wave > 180 then
		return (wave - 180) * 65 + 4100
	elseif wave > 170 then
		return (wave - 170) * 60 + 3500
	elseif wave > 160 then
		return (wave - 160) * 55 + 2950
	elseif wave > 150 then
		return (wave - 150) * 50 + 2450
	elseif wave > 140 then
		return (wave - 140) * 45 + 2000
	elseif wave > 130 then
		return (wave - 130) * 40 + 1600
	elseif wave > 120 then
		return (wave - 120) * 35 + 1250
	elseif wave > 110 then
		return (wave - 110) * 30 + 950
	elseif wave > 100 then
		return (wave - 100) * 25 + 700
	elseif wave > 90 then
		return (wave - 90) * 20 + 500
	elseif wave > 80 then
		return (wave - 80) * 16 + 340
	elseif wave > 70 then
		return (wave - 70) * 12 + 220
	elseif wave > 60 then
		return (wave - 60) * 8 + 140
	elseif wave > 50 then
		return (wave - 50) * 4 + 100
	elseif wave > 0 then
		return wave * 2
	else
		return 1
	end
end

-- 清除已移除刷怪点
function SpawnSystem:ClearRemovedSpawner()	
	local spawner = SpawnSystem.AttackingSpawner	
	if spawner == nil or #spawner == 0 then return end
	for i = #spawner, 1, -1 do
		if spawner[i].hero.is_game_over == true then
			THTD_EntitiesRectInner[spawner[i].hero.thtd_player_id] = {}
			table.remove(spawner, i)			
		end
	end	
end

-- 刷新漏怪最大数
function SpawnSystem:RefreshCreepMaxCount()
	for _,hero in pairs(GameRules.HeroList) do	
		if SpawnSystem.IsUnLimited then 
			hero.thtd_game_info["creep_count_max"] = 20
		else			
			hero.thtd_game_info["creep_count_max"] = 30 * SpawnSystem:GetCount()
		end
	end
end


-- 战利品奖励，同步更新下pet对应技能

local T1 = {
	"item_2004",
	"item_3022", --金币满箱	
}
local T2 = {
	"item_2022",
	"item_2003",
	
	"item_3012", --幸运者的烦恼
	"item_3018", --亲友折扣	
	"item_3029", --四季馈赠
}
local T3 = {
	"item_2002",	
	"item_2012",
	"item_2013",
	"item_2014",

	"item_3017", --一线希望
	"item_3019", --绝望手段
	"item_3020", --扩大阵容
	"item_3026", --口袋细沙
}
local T4 = {
	"item_2001",
	
	"item_3013", --无敌意识 负页效果降低
	"item_3014", --战斗中铸就 主角
	"item_3016", --召唤神石
	"item_3030", --人多力量大 分身	
	"item_3021", --邪恶意念 秒杀	
}
local T5 = {	
	"item_3011", --烁热同盟	  地灵殿	
	"item_3015", --失去天恩  月之民
	"item_3028", --大力一击 鬼族
	"item_3023", --虹吸意图 神灵庙
	"item_3024", --香火长存 守矢神社
	"item_3025", --终极闪烁 红魔馆
	"item_3027", --鉴宝大师 星莲船	
}

local battle_bonus_list = 
{
	[10] = {
		[1] = T1,
		[2] = T2,			
	},
	[20] = {
		[1] = T2,
		[2] = T3,
	},
	[30] = {
		[1] = T3,
		[2] = T4,
	},
	[40] = {
		[1] = T4,
		[2] = T5,
	},
	[50] = {
		[1] = T5,
		[2] = {},
	},
}

-- 战利品奖励
function SpawnSystem:OnBattleBonusWaveOld(hero)
	if SpawnSystem.IsUnLimited then return end

	local wave = SpawnSystem.CurWave
	if battle_bonus_list[wave] == nil then return end

	local bonusList1 = {}
	local bonusList2 = {}
	
	for k,v in pairs(battle_bonus_list[wave][1]) do
		table.insert(bonusList1, v)
	end
	for k,v in pairs(battle_bonus_list[wave][2]) do
		table.insert(bonusList2, v)
	end

	local maxCount = 2
	if hero.reimu_pet.pet_level >= 20 then 
		maxCount = 4 + math.floor(hero.reimu_pet.pet_level/20)
	elseif hero.reimu_pet.pet_level >= 10 then
		maxCount = 4
	elseif hero.reimu_pet.pet_level >= 5 then
		maxCount = 3
	end	
	if GameRules.GameData.is_open_day == 1 then maxCount = math.max(5, maxCount) end
	
	local select_cards = {}

	for i=1,maxCount do
		local chance = RandomInt(1,100)
		if #bonusList2 == 0 then chance = 100 end
		if chance > 30 and #bonusList1 > 0 then
			local k = RandomInt(1, #bonusList1)			
			select_cards[bonusList1[k]] = bonusList1[k]
			table.remove(bonusList1, k)
		elseif #bonusList2 > 0 then
			local k = RandomInt(1, #bonusList2)			
			select_cards[bonusList2[k]] = bonusList2[k]
			table.remove(bonusList2, k)
		end
	end
	
	bonusList1 = {}
	bonusList2 = {}

	for i=maxCount+1, 5 do
		select_cards["item_3050_"..tostring(i)] = "item_3050"
	end

	CustomGameEventManager:Send_ServerToPlayer(hero:GetPlayerOwner(), "show_select_bonus_card_panel", {cards=select_cards})
end

-- 战利品奖励
function SpawnSystem:OnBattleBonusWave(hero)
	if SpawnSystem.IsUnLimited then return end

	local wave = SpawnSystem.CurWave
	if battle_bonus_list[wave] == nil then return end

	-- 调整为改善运营

	local bonusList1 = {}
	local bonusList2 = {}
	local chanceBonusPoint = 30

	if wave == 10 then 
		for k,v in pairs(towerNameList) do
			if v["quality"] == 2 and v["cardname"] ~= "BonusEgg" then
				table.insert(bonusList1, k)			
			end
		end
	elseif wave == 20 then 
		for k,v in pairs(towerNameList) do
			if v["quality"] == 2 and v["cardname"] ~= "BonusEgg" then
				table.insert(bonusList1, k)	
			elseif v["quality"] == 3 and v["cardname"] ~= "BonusEgg" then
				table.insert(bonusList2, k)	
			end
		end
	elseif wave == 30 then 
		for k,v in pairs(towerNameList) do
			if v["quality"] == 3 and v["cardname"] ~= "BonusEgg" then
				table.insert(bonusList1, k)	
			elseif v["quality"] == 4 and v["cardname"] ~= "BonusEgg" then
				table.insert(bonusList2, k)	
			end
		end
	elseif wave == 40 then 
		chanceBonusPoint = 50
		for k,v in pairs(towerNameList) do
			if v["quality"] == 3 and v["cardname"] ~= "BonusEgg" then
				table.insert(bonusList1, k)	
			elseif v["quality"] == 4 and v["cardname"] ~= "BonusEgg" then
				table.insert(bonusList2, k)	
			end
		end
	elseif wave == 50 then 
		for k,v in pairs(towerNameList) do
			if v["quality"] == 4 and v["cardname"] ~= "BonusEgg" then
				table.insert(bonusList1, k)	
			end
		end
	end

	local maxCount = 3
	if hero.reimu_pet.pet_level >= 5 then
		maxCount = 3 + math.floor(hero.reimu_pet.pet_level/5)
	end	
	if GameRules.GameData.is_open_day == 1 then maxCount = math.max(6, maxCount) end	

	local select_cards = {}

	for i=1,maxCount do
		local chance = RandomInt(1,100)
		if #bonusList2 == 0 then chance = 100 end
		if chance > chanceBonusPoint and #bonusList1 > 0 then
			local k = RandomInt(1, #bonusList1)			
			select_cards[bonusList1[k]] = bonusList1[k]
			table.remove(bonusList1, k)
		elseif #bonusList2 > 0 then
			local k = RandomInt(1, #bonusList2)			
			select_cards[bonusList2[k]] = bonusList2[k]
			table.remove(bonusList2, k)
		end
	end

	if maxCount < #bonusList1 + #bonusList2 then
		select_cards["item_3050"] = "item_3050"
	end

	bonusList1 = {}
	bonusList2 = {}

	CustomGameEventManager:Send_ServerToPlayer(hero:GetPlayerOwner(), "show_select_bonus_card_panel", {cards=select_cards})
end