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("clear the same rank : "..json.encode(toDelList).."", 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() 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