Files
2HUCardTDGame/scripts/vscripts/system/spawner.lua
2022-07-23 00:21:14 -04:00

1955 lines
62 KiB
Lua
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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