c1_lua/lua/app/module/battle/controller/battle_controller.lua
2023-04-19 15:49:58 +08:00

1475 lines
47 KiB
Lua
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.

local BattleHelper = require "app/module/battle/helper/battle_helper"
local BattleScheduler = require "app/module/battle/helper/battle_scheduler"
local BattleTeam = require "app/module/battle/team/battle_team"
local BattlePassive = require "app/module/battle/helper/battle_passive"
local BattleController = class("BattleController")
local BATTLE_BOARD_SKILL_HANDLE = require "app/module/battle/skill/battle_board_skill_handle"
local BATTLE_ROGUE_SKILL_HANDLE = require "app/module/battle/skill/battle_rogue_skill_handle"
local BattleBuffHandle = require "app/module/battle/helper/battle_buff_handle"
local ELIMINATION_TOUCH_EVENT = GConst.ELIMINATION_TOUCH_EVENT
local BattleConst = GConst.BattleConst
local BUFF_NAME_TO_ATTR = BattleConst.BUFF_NAME_TO_ATTR
-- *************各个子模块的战斗需要重写的方法 START*************
function BattleController:getChapterId()
return 0
end
function BattleController:getInitBoard()
return {}
end
function BattleController:getNotInvolvedSkills()
return {}
end
function BattleController:getSealElementType()
return {}
end
-- 战斗对应的ui
function BattleController:getBattleUIPath()
return "app/ui/battle/battle_ui"
end
-- 战斗结束
function BattleController:controllBattleEnd()
end
-- 不同模块的战斗需要初始化的东西
function BattleController:initOther()
end
-- 需要额外加载的资源
function BattleController:loadOtherRes(callback)
return callback()
end
-- 一共有多少波
function BattleController:getMaxWave()
return 1
end
function BattleController:getMinEliminationCount()
if not self.minEliminationCount then
self.minEliminationCount = GFunc.getConstIntValue("element_combo")
end
return self.minEliminationCount
end
function BattleController:initDefUnits(callback)
callback()
end
function BattleController:findNextDefUnit()
self:enterRefreshBoard()
end
function BattleController:tick(dt)
end
function BattleController:onLinkChange()
for posId, entity in pairs(self.battleData:getGridEnties()) do
if entity:getCell() then
entity:getCell():showHighLight(false)
end
end
local sequence = self.battleData:getGridSequence()
local elementTypeMap = {}
local posIdMap = {}
local mainElementType
for _, info in ipairs(sequence) do
posIdMap[info.posId] = true
local entity = self.battleData:getGridEntity(info.posId)
if not entity:getSkillId() then
local elementType = entity:getElementType()
elementTypeMap[elementType] = (elementTypeMap[elementType] or 0) + 1
mainElementType = elementType
end
end
for _, info in ipairs(sequence) do
local entity = self.battleData:getGridEntity(info.posId)
if entity:getCell() then
entity:getCell():showHighLight(true, mainElementType)
end
end
for posId, info in pairs(self.battleData:getSkillInfluenceGrids()) do
local entity = self.battleData:getGridEntity(posId)
if not posIdMap[posId] and info.direction ~= BattleConst.BOARD_RANGE_TYPE.RANDOM then
posIdMap[posId] = true
if not entity:getSkillId() then
local elementType = entity:getElementType()
elementTypeMap[elementType] = (elementTypeMap[elementType] or 0) + 1
end
if entity:getCell() then
entity:getCell():showCircle(true)
end
end
end
self.battleUI:refreshSkill(elementTypeMap)
if mainElementType then
self.atkTeam:changeMainUnit(mainElementType)
end
end
function BattleController:onRoundBegin()
end
function BattleController:onEliminationBegin()
end
-- *************各个子模块的战斗需要重写的方法 END*************
function BattleController:ctor()
self.battleData = DataManager.BattleData
end
function BattleController:init(params)
params = params or {}
self.chapterId = self:getChapterId()
self.waveIndex = 0
self.maxWaveIndex = self:getMaxWave()
self.victory = false
self.roundStep = BattleConst.BATTLE_ROUND_STEP.WAIT_BEGIN
self.effectTexts = {}
self.instructions = {}
self.time = 0
self.battleData:init()
BattleScheduler:init()
BattleHelper:init()
BattlePassive:init()
self:setTimeScale(DataManager.BattleData:getTimeScale())
self:bindData()
self:initBattleTeam()
self:initOther()
self:prepareFight()
end
function BattleController:bindData()
DataManager.BattleData:bind("timeSpeed", ModuleManager.BattleManager, function()
self:setTimeScale(DataManager.BattleData:getTimeScale())
end, false)
end
function BattleController:unBindAll()
DataManager.BattleData:unBind("timeSpeed", ModuleManager.BattleManager)
end
function BattleController:initBattleTeam()
self.atkTeam = BattleTeam:create()
self.atkTeam:init(BattleConst.SIDE_ATK, self)
self.defTeam = BattleTeam:create()
self.defTeam:init(BattleConst.SIDE_DEF, self)
end
function BattleController:setIsPauseHpProgress(value)
self.battleUI:setIsPauseHpProgress(value)
end
function BattleController:prepareFight()
local count = 0
local totalCount = 3
local function onPreloadFinished()
count = count + 1
if count == totalCount then
self:onLoadComplete()
end
end
UIManager:closeAllUI()
self.battleUI = UIManager:showUI(self:getBattleUIPath())
self.battleUI:setController(self)
self.battleUI:addLoadUICompleteListener(function()
BattleHelper:setEffectTextCache(self.battleUI:getBattleNumber())
self:initAtkUnits(onPreloadFinished)
self:initDefUnits(onPreloadFinished)
end)
self:loadOtherRes(onPreloadFinished)
end
function BattleController:initAtkUnits(callback)
local atkTeamEntity = self.battleData:getAtkTeam()
local count = 0
local totalCount = atkTeamEntity:getMembersCount()
local function onloadFinished()
count = count + 1
if count == totalCount then
self.battleUI:refreshAtkHp(atkTeamEntity:getHp(), atkTeamEntity:getHpPercent())
callback()
end
end
local members = atkTeamEntity:getAllMembers()
for k, v in pairs(members) do
local modelId = v:getModelId()
BattleHelper:loadBattleHeroModel(modelId, self.battleUI:getBattleNode(), function(spineObject)
local heroComp = spineObject:addLuaComponent(BattleConst.TYPEOF_LUA_COMP.BATTLE_HERO_COMPONENT)
heroComp:initWithEntity(modelId, v, self)
if v:getIsMainUnit() then
self.atkTeam:addUnit(heroComp, true)
else
self.atkTeam:addUnit(heroComp)
heroComp:hideOutsideScreen()
end
onloadFinished()
end)
end
if totalCount == 0 then
callback()
end
end
function BattleController:refreshHp(side, num, percent)
if side == BattleConst.SIDE_ATK then
self.battleUI:refreshAtkHp(num, percent)
else
self.battleUI:refreshDefHp(num, percent)
end
end
function BattleController:getOtherSideMainUnit(side)
if side == BattleConst.SIDE_ATK then
return self.defTeam:getMainUnit()
else
return self.atkTeam:getMainUnit()
end
end
function BattleController:onLoadComplete()
self:battleStart()
end
function BattleController:battleStart()
self.atkTeam:prepare()
self.defTeam:prepare()
self.isBattleStart = true
self.tickSid = BattleScheduler:scheduleGlobal(function(dt)
self:_tick(dt)
end, 0)
self:enterNextWave()
end
function BattleController:setTimeScale(timeScale)
GFunc.setDOTweenTimeScale(GConst.DOTWEEN_IDS.BATTLE, timeScale)
BattleScheduler:setTimeScale(timeScale)
BattleHelper:setTimeScale(timeScale)
end
---- start 回合步骤
function BattleController:enterNextWave()
local atkTeam = self.battleData:getAtkTeam()
if not atkTeam or atkTeam:getIsDead() then
self.victory = false
self:battleEnd()
return
end
if self.waveIndex >= self.maxWaveIndex then
self.victory = true
self:battleEnd()
return
end
self.waveIndex = self.waveIndex + 1
if self.battleUI then
self.battleUI:refreshWave(self.waveIndex)
end
if self.waveIndex == 1 then -- 第一波
self.isBossWave = self.defTeam:getMainUnit().unitEntity:getIsBoss()
self:generateBoard()
return
end
self.defTeam:prepare()
if self.isBossWave then -- 如果上一波是boss波次则重新生成棋盘
self:putBoardCacheSkill(function()
self:generateBoard()
end)
else
self:enterRoundBegin()
end
self.isBossWave = self.defTeam:getMainUnit().unitEntity:getIsBoss()
end
function BattleController:enterRoundBegin()
self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_BEGIN
self:onRoundBegin()
self:enterEliminationBegin()
end
function BattleController:enterEliminationBegin()
self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_BEGIN
self:onEliminationBegin()
self:popBoardCacheSkill(function()
self:enterElimination()
end)
end
function BattleController:enterElimination()
self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_ELIMINATION
end
function BattleController:enterAtkStep()
self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_ATK_STEP
self:exeInstructions(function()
self:enterAtkStepOver()
end)
end
function BattleController:enterAtkStepOver()
self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_ATK_STEP_OVER
local defTeam = self.battleData:getDefTeam()
if not defTeam or defTeam:getIsDead() then -- 怪物死了, 直接进入刷新逻辑
if self.waveIndex >= self.maxWaveIndex then
self:enterRoundEnd()
else
self:findNextDefUnit()
end
return
end
local atkTeam = self.battleData:getAtkTeam()
if not atkTeam or atkTeam:getIsDead() then -- 英雄死了, 直接结算
self:enterNextWave()
return
end
self:enterDefStep()
end
function BattleController:enterDefStep()
self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_DEF_STEP
self.defTeam:mainUnitUseAllSkills(function()
self:enterDefStepOver()
end)
end
function BattleController:enterDefStepOver()
self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_DEF_STEP_OVER
local atkTeam = self.battleData:getAtkTeam()
if not atkTeam or atkTeam:getIsDead() then -- 英雄死了, 直接结算
self:enterNextWave()
return
end
local defTeam = self.battleData:getDefTeam()
if not defTeam or defTeam:getIsDead() then -- 怪物死了, 直接进入刷新逻辑
if self.waveIndex >= self.maxWaveIndex then
self:enterRoundEnd()
else
self:findNextDefUnit()
end
return
end
---- 临时直接调用
self:enterRefreshBoard()
end
function BattleController:enterRefreshBoard()
self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_REFRESH_BOARD
self:fillBoard()
end
function BattleController:enterRoundEnd()
self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_END
local defTeam = self.battleData:getDefTeam()
if not defTeam or defTeam:getIsDead() then -- 怪物死了, 直接进入刷新逻辑
self.atkTeam:onRoundEnd()
self:enterNextWave()
return
end
local atkTeam = self.battleData:getAtkTeam()
if not atkTeam or atkTeam:getIsDead() then -- 英雄死了, 直接结算
self.defTeam:onRoundEnd()
self:enterNextWave()
return
end
self.atkTeam:onRoundEnd()
self.defTeam:onRoundEnd()
if self.battleData:useAddlvCount() then
ModuleManager.BattleManager:showSelectSkillUI(self:getRandomSkillList())
else
self:enterRoundBegin()
end
end
---- end回合步骤
function BattleController:onTouchEvent(eventType, posId)
if self.roundStep ~= BattleConst.BATTLE_ROUND_STEP.ON_ELIMINATION then
return
end
local entity = self.battleData:getGridEntity(posId)
if not entity or not entity:canLink() then
return
end
if eventType == ELIMINATION_TOUCH_EVENT.DOWN then
if #self.battleData:getGridSequence() > 0 then
self.battleData:clearGridSequence()
end
self.battleData:insertGridSequence(posId, self:snapshotBoard())
local skillEntity = self.battleData:getSkillEntityBySkillId(entity:getSkillId())
local maskElementType = entity:getElementType(skillEntity)
self.battleUI:showBoardMask(maskElementType)
self:findSkillInfluenceGrids()
self:onLinkChange()
elseif eventType == ELIMINATION_TOUCH_EVENT.ENTER then
local sequence = self.battleData:getGridSequence()
local info = sequence[#sequence]
local lastPosId = info and info.posId
if not lastPosId then
return
end
local outLineMap = BattleConst.GRID_OUT_LINE_POS_ID[lastPosId]
if not outLineMap or not outLineMap[posId] then
return
end
if self.battleData:alreadyInsertSequence(posId) then
local info = sequence[#sequence - 1]
local beforePosId = info and info.posId
if not beforePosId then
return
end
if beforePosId == posId then -- 进入的是倒数第二个,则移除倒数第一个
local snapshot = self.battleData:removeGridSequence(lastPosId)
if snapshot then -- 如果有快照,则恢复一次
for posId, info in pairs(snapshot) do
local entity = self.battleData:getGridEntity(posId)
if entity then
entity:setInfoBySnapshop(info)
end
end
end
local lastEntity = self.battleData:getGridEntity(beforePosId)
local lastSkillEntity = self.battleData:getSkillEntityBySkillId(lastEntity:getSkillId())
local maskElementType = lastEntity:getElementType(lastSkillEntity)
self.battleUI:showBoardMask(maskElementType)
self:findSkillInfluenceGrids()
self:onLinkChange()
return
end
end
local skillId = entity:getSkillId()
local skillEntity = self.battleData:getSkillEntityBySkillId(skillId)
local elementType = entity:getElementType(skillEntity)
local lastEntity = self.battleData:getGridEntity(lastPosId)
local lastSkillId = lastEntity:getSkillId()
local lastSkillEntity = self.battleData:getSkillEntityBySkillId(lastSkillId)
local lastElementType = lastEntity:getElementType(lastSkillEntity)
if skillEntity and self.battleData:getSequenceHadSkill() then
return
end
if not elementType or not lastElementType then
else
if lastElementType ~= elementType then
return
end
end
local maskElementType = elementType or lastElementType
self.battleUI:showBoardMask(maskElementType)
self.battleData:insertGridSequence(posId, self:snapshotBoard())
if lastEntity:getNeedChangePos() and not entity:getNeedChangePos() then -- 需要移动到队列末尾
local lastSkillId = lastEntity:getSkillId()
local skillId = entity:getSkillId()
self:setGridSkillId(lastPosId, skillId)
self:setGridSkillId(posId, lastSkillId)
end
local newElementType = elementType or lastElementType
if newElementType then
entity:setElementType(newElementType)
lastEntity:setElementType(newElementType)
end
entity:addLinkSkillCount()
self:findSkillInfluenceGrids()
self:onLinkChange()
elseif eventType == ELIMINATION_TOUCH_EVENT.EXIT then
else -- 取消和抬起
self.battleUI:showBoardMask(nil)
local sequence = self.battleData:getGridSequence()
local count = #sequence
if count < self:getMinEliminationCount() then
if count <= 0 then
self.battleData:clearGridSequence()
self:onLinkChange()
return
end
local snapshot = self.battleData:removeGridSequence(sequence[1].posId)
if snapshot then -- 如果有快照,则恢复一次
for posId, info in pairs(snapshot) do
local entity = self.battleData:getGridEntity(posId)
if entity then
entity:setInfoBySnapshop(info)
end
end
end
self.battleData:clearGridSequence()
self:onLinkChange()
return
end
self:onLinkOver()
end
end
function BattleController:onLinkOver()
local sequence = self.battleData:getGridSequence()
local count = #sequence
if count < self:getMinEliminationCount() then
return
end
local skillId = self.battleData:getSequenceHadSkill()
local skillEntity
local linkElementType
local influenceElementType
if skillId then
skillEntity = self.battleData:getSkillEntityBySkillId(skillId)
end
local elementTypeMap = {}
local eliminationPosIds = {}
local boomGridIds = {}
local lineCount = 0
for _, info in ipairs(sequence) do
if not eliminationPosIds[info.posId] then
local entity = self.battleData:getGridEntity(info.posId)
if not entity:getSkillId() then
local elementType = entity:getElementType()
elementTypeMap[elementType] = (elementTypeMap[elementType] or 0) + 1
linkElementType = elementType
lineCount = lineCount + 1
end
local outline = BattleConst.GRID_OUT_LINE_POS_ID[info.posId]
for aroundPosId, _ in pairs(outline) do
boomGridIds[aroundPosId] = true
end
local entity = self.battleData:getGridEntity(info.posId)
entity:setIsIdle(true)
eliminationPosIds[info.posId] = true
end
end
for posId, _ in pairs(self.battleData:getSkillInfluenceGrids()) do
local entity = self.battleData:getGridEntity(posId)
if not entity:getIsIdle() then
if entity:isEmptyIdle() then
entity:setIsIdle(true)
if not eliminationPosIds[posId] then
eliminationPosIds[posId] = true
table.insert(sequence, {posId = posId})
end
if not entity:getSkillId() then
local elementType = entity:getElementType()
elementTypeMap[elementType] = (elementTypeMap[elementType] or 0) + 1
if not influenceElementType then
influenceElementType = {}
end
influenceElementType[elementType] = true
end
else
boomGridIds[posId] = true
end
end
end
for posId, status in pairs(boomGridIds) do
if not eliminationPosIds[posId] then
local entity = self.battleData:getGridEntity(posId)
if entity then
local elementTypeInvalid = entity:isElmentTypeInvalid()
entity:addAroundEliminationCount()
if entity:getIsIdle() then
eliminationPosIds[posId] = true
table.insert(sequence, {posId = posId, noAni = elementTypeInvalid})
if not entity:getSkillId() and not elementTypeInvalid then
local elementType = entity:getElementType()
elementTypeMap[elementType] = (elementTypeMap[elementType] or 0) + 1
end
end
end
end
end
self.battleData:addSkillEnergy(elementTypeMap)
self.battleData:clearGridSequence()
self.battleUI:disableUITouch()
self.battleUI:eliminationAni(sequence, function()
self:generateInstructions(skillEntity, linkElementType, lineCount, influenceElementType, elementTypeMap)
self:enterAtkStep()
end)
end
function BattleController:fillBoard()
local pathMap = {}
local columnCount = {}
local gridMap = {}
for c = 1, BattleConst.COLUMN_COUNT do
for r = BattleConst.ROW_COUNT, 1, -1 do
local posId = ModuleManager.BattleManager:getPosId(r, c)
local entity = self.battleData:getGridEntity(posId)
if entity:getIsIdle() then
self:fillThisPos(posId, columnCount, gridMap)
end
end
end
while true do
local find = false
for c = 1, BattleConst.COLUMN_COUNT do
local list = gridMap[c]
if list and list[1] then -- 此列有需要填充的元素
local entity = table.remove(list, 1)
if entity then
self.battleData:setGridInfo(entity:getPosId(), self:getRandomGridInfo())
end
find = true
end
end
if not find then
break
end
end
for c = 1, BattleConst.COLUMN_COUNT do
for r = BattleConst.ROW_COUNT, 1, -1 do
local posId = ModuleManager.BattleManager:getPosId(r, c)
local entity = self.battleData:getGridEntity(posId)
if #entity:getPath() > 0 then
pathMap[posId] = entity:getPath()
entity:clearPath()
end
end
end
self.battleUI:fallGrid(pathMap, function()
self:onFillBoardOver()
self.battleUI:enableUITouch()
end)
end
function BattleController:onFillBoardOver()
self:generateSkill(function()
self.battleUI:refreshSkill()
self:enterRoundEnd()
end)
end
function BattleController:generateInstructions(skillEntity, elementType, lineCount, influenceElementTypeMap, elementTypeMap)
local elementTypeCount = 0
local assistingList = nil
---- 援助
for element, count in pairs(elementTypeMap) do
if element == elementType then
elementTypeCount = count
else
if assistingList == nil then
assistingList = {}
end
local obj = {
count = count,
skillMatch = element,
}
table.insert(assistingList, obj)
end
end
---- 技能
if skillEntity then
table.insert(self.instructions, {
name = BattleConst.INSTRUCTION_NAME.PLAY_SKILL,
skillMatch = elementType,
count = elementTypeCount,
})
else
---- 普攻
if elementTypeCount > 0 then
table.insert(self.instructions, {
name = BattleConst.INSTRUCTION_NAME.GENERAL_ATTACK,
skillMatch = elementType,
count = elementTypeCount,
})
end
end
if assistingList then
table.insert(self.instructions, {
name = BattleConst.INSTRUCTION_NAME.ASSISTING,
assistingList = assistingList,
})
end
---- 加buff
if skillEntity then
if skillEntity:getLinkEffects() and elementType then
local effectList
for type, buffEntities in pairs(skillEntity:getLinkEffects()) do
local buffEntity = buffEntities[elementType]
if buffEntity then
if not effectList then
effectList = {}
end
table.insert(effectList, buffEntity)
end
end
if effectList then
local unit = {
name = BattleConst.INSTRUCTION_NAME.ADD_CUR_ROUND_ATTR,
effectList = effectList
}
table.insert(self.instructions, unit)
end
end
if skillEntity:getInInfluenceEffects() and influenceElementTypeMap then
for influenceElementType , _ in pairs(influenceElementTypeMap) do
local effectList
for type, buffEntities in pairs(skillEntity:getInInfluenceEffects()) do
local buffEntity = buffEntities[influenceElementType]
if buffEntity then
if not effectList then
effectList = {}
end
table.insert(effectList, buffEntity)
end
end
if effectList then
table.insert(self.instructions, {
name = BattleConst.INSTRUCTION_NAME.ADD_CUR_ROUND_ATTR,
effectList = effectList
})
end
end
end
if skillEntity:getElementCountEffect() and elementType then
local effectList
for type, buffEntities in pairs(skillEntity:getElementCountEffect()) do
local originBuffEntity = buffEntities.origin
local useBuffEntity = buffEntities.use
if not effectList then
effectList = {}
end
local newNum = originBuffEntity:getEffectNum() * lineCount
useBuffEntity:setEffectNum(newNum)
table.insert(effectList, useBuffEntity)
end
if effectList then
table.insert(self.instructions, {
name = BattleConst.INSTRUCTION_NAME.ADD_CUR_ROUND_ATTR,
effectList = effectList
})
end
end
--
if skillEntity:getSkillAttackBeforeEffects() and elementType then
local effectList
for type, buffEntity in pairs(skillEntity:getSkillAttackBeforeEffects()) do
if not effectList then
effectList = {}
end
table.insert(effectList, buffEntity)
end
if effectList then
table.insert(self.instructions, {
name = BattleConst.INSTRUCTION_NAME.ADD_CUR_ROUND_ATTR,
effectList = effectList
})
end
end
end
end
function BattleController:exeInstructions(callback)
Logger.logHighlight("--------exeInstructions----------")
if not self.instructions or #self.instructions <= 0 then
callback()
return
end
local instruction = table.remove(self.instructions)
local func = BattleController._doInstruction[instruction.name]
if func then
func(self, instruction, function()
DataManager.BattleData:resetTimeSpeed()
self:exeInstructions(callback)
end)
else
self:exeInstructions(callback)
end
end
function BattleController:generateBoard()
local boardList, _ = self:getInitBoard()
if self.curBoardIndex and self.curBoardIndex >= #boardList then
return
end
if not self.battleUI then
return
end
self.curBoardIndex = (self.curBoardIndex or 0) + 1
local board = boardList[self.curBoardIndex]
self.battleData:refreshBoard(board)
self.battleUI:initGridCell()
self:enterRoundBegin()
end
function BattleController:putBoardCacheSkill(callback)
if not self.battleUI then
return
end
self.battleData:cacheBoardSkill()
local skillList, skillCount = self.battleData:getCacheBoardSkill()
self.battleUI:cacheSkillAni(skillList, false, callback)
end
function BattleController:popBoardCacheSkill(callback)
local skillList, skillCount = self.battleData:getCacheBoardSkill()
self.battleData:clearCacheBoardSkill()
if self.battleUI and skillCount > 0 then
local posidList = {}
for posId, entity in pairs(self.battleData:getGridEnties()) do
if entity:isEmptyIdle() then
table.insert(posidList, posId)
end
end
posidList = table.shuffle(posidList)
local newSkillId = {}
for index, info in ipairs(skillList) do
if posidList[1] then
newSkillId[index] = info
newSkillId[index].posId = table.remove(posidList)
else
break
end
end
self.battleUI:cacheSkillAni(newSkillId, true, callback)
else
if callback then
callback()
end
end
end
function BattleController:generateSkill(callback)
local map = {}
local excludeMap = {}
for _, skillEntity in pairs(self.battleData:getSkillEntities()) do
if skillEntity:getEnergyEnough() then
local list = self:getSkillElementList(skillEntity:getPosition(), 1, true, excludeMap)
if list[1] then
map[skillEntity:getPosition()] =
{
skillId = skillEntity:getSkillId(),
posId = list[1]
}
excludeMap[list[1]] = true
end
end
end
if not self.battleUI then
if callback then
callback()
end
return
end
self.battleUI:generateSkillAni(map, function()
for elementType, info in pairs(map) do
self:setGridSkillId(info.posId, info.skillId)
end
if callback then
callback()
end
end)
end
function BattleController:setGridSkillId(posId, skillId)
local entity = self.battleData:getGridEntity(posId)
if entity then
entity:setSkilId(skillId)
local skillEntity = self.battleData:getSkillEntityBySkillId(skillId)
if skillEntity and entity:getElementType() ~= skillEntity:getPosition() then
entity:setElementType(skillEntity:getPosition())
end
end
end
function BattleController:generateGridType(gridType)
if not gridType then
return
end
local list = {}
local count = 0
for posId, entity in pairs(self.battleData:getGridEnties()) do
if entity:isEmptyIdle() then
table.insert(list, entity)
count = count + 1
end
end
if count > 0 then
local entity = list[math.random(1, count)]
self.battleData:setGridInfo(entity:getPosId(), {gridType = gridType, elementType = entity:getElementType()})
end
end
function BattleController:getSkillElementList(elementType, count, useAlternate, excludeMap)
local result = {}
local gridEntities = self.battleData:getGridEnties()
if not gridEntities then
return result
end
local sameElementList = {}
local alternateList = {}
local addCount = 0
for row = 1, BattleConst.ROW_COUNT do
for column = 1, BattleConst.COLUMN_COUNT do
local posId = ModuleManager.BattleManager:getPosId(row, column)
local entity = gridEntities[posId]
if entity and entity:canChangeInfo() and not excludeMap[posId] then
if entity:getElementType() == elementType then
table.insert(sameElementList, posId)
else
table.insert(alternateList, posId)
end
end
end
local remainCount = count - addCount
if remainCount <= 0 then
return result
end
for i = 1, remainCount do
if not sameElementList[i] then
break
end
table.insert(result, table.remove(sameElementList, math.random(1, #sameElementList)))
addCount = addCount + 1
if addCount >= count then
return result
end
end
if addCount < count and useAlternate then
for i = 1, count - addCount do
if not alternateList[1] then
break
end
table.insert(result, table.remove(alternateList, math.random(1, #alternateList)))
addCount = addCount + 1
if addCount >= count then
return result
end
end
end
if addCount >= count then
return result
end
end
return result
end
---- 从一个点直接遍历所有相关的路径
function BattleController:fillThisPos(posId, columnCount, gridMap)
local entity = self.battleData:getGridEntity(posId)
if not entity or not entity:getIsIdle() then
return
end
local list = BattleConst.UP_LINE_FILL_LIST[posId]
if not list[1] then -- 第一排
local rc = ModuleManager.BattleManager:getPosRC(posId)
local c = rc.c
if not columnCount[c] then
columnCount[c] = 0
end
columnCount[c] = columnCount[c] + 1
local fallPosId = posId
local fallEntity = self.battleData:getGridEntity(fallPosId)
if not fallEntity then -- 异常情况,理论上不可能不存在
return
end
local newStartPosId
for i = columnCount[c], 1, -1 do
newStartPosId = ModuleManager.BattleManager:getFirstLineLastRowPosId(i, c)
local curPos = ModuleManager.BattleManager:getPosInfo(newStartPosId)
fallEntity:addPath({x = curPos.x, y = curPos.y})
end
local curPos = ModuleManager.BattleManager:getPosInfo(posId)
fallEntity:addPath({x = curPos.x, y = curPos.y})
self.battleData:exchangeGridEntities(posId, fallPosId)
if not gridMap[c] then
gridMap[c] = {}
end
table.insert(gridMap[c], fallEntity)
else
for index, fallPosId in ipairs(list) do
local fallEntity = self.battleData:getGridEntity(fallPosId)
if not fallEntity then -- 异常情况,理论上不可能不存在
return
end
if fallEntity then
if not fallEntity:isCantFallType() then
if fallEntity:getIsIdle() then
self:fillThisPos(fallPosId, columnCount, gridMap)
end
fallEntity = self.battleData:getGridEntity(fallPosId)
if not fallEntity:getIsIdle() then
if not fallEntity:getPath()[1] then
local curPos = ModuleManager.BattleManager:getPosInfo(fallPosId)
fallEntity:addPath({x = curPos.x, y = curPos.y})
end
local curPos = ModuleManager.BattleManager:getPosInfo(posId)
fallEntity:addPath({x = curPos.x, y = curPos.y})
self.battleData:exchangeGridEntities(posId, fallPosId)
self:fillThisPos(fallPosId, columnCount, gridMap)
return
end
end
end
end
end
end
function BattleController:getRandomGridInfo()
local list, fixedRandomGrid = self:getInitBoard()
local fixedRandomList = fixedRandomGrid[self.curBoardIndex]
local gridType = 0
local elementType
if fixedRandomList and fixedRandomList[1] then
elementType = table.remove(fixedRandomList, 1)
else
local map = self.battleData:getElementTypeMap()
local indexs = {}
local typeList = {}
for typeName, typeNum in pairs(BattleConst.ELEMENT_TYPE) do
if not self:getSealElementType()[typeNum] and self.battleData:getSkillEntityByElement(typeNum) then
local weight = ((map[typeNum] or 0) + 1) * BattleConst.ELEMENT_WIGHT
if weight > BattleConst.MAX_ELEMENT_WIGHT then
weight = BattleConst.MAX_ELEMENT_WIGHT
end
table.insert(indexs, weight)
table.insert(typeList, typeNum)
end
end
local index = GFunc.getRandomIndex(indexs)
elementType = typeList[index]
end
return {gridType = gridType, elementType = elementType}
end
function BattleController:findSkillInfluenceGrids()
local girds = self.battleData:clearSkillInfluenceGrids()
for posId, _ in pairs(girds) do
local entity = self.battleData:getGridEntity(posId)
if entity:getCell() then
entity:getCell():showCircle(false)
end
end
local sequence = self.battleData:getGridSequence()
local sequenceEntities = {}
for _, info in ipairs(sequence) do
local entity = self.battleData:getGridEntity(info.posId)
table.insert(sequenceEntities, entity)
end
for _, info in ipairs(sequence) do
local entity = self.battleData:getGridEntity(info.posId)
local skillId = entity:getSkillId()
if skillId then
local skillEntity = self.battleData:getSkillEntityBySkillId(skillId)
if skillEntity then
BATTLE_BOARD_SKILL_HANDLE.activeBoardSkill(info.posId, skillEntity, self.battleData:getGridEnties(), sequenceEntities)
end
end
end
end
function BattleController:getRandomSkillList(getCount)
getCount = getCount or BattleConst.SKILL_SELECT_COUNT
local result = {}
local cfg = ConfigManager:getConfig("skill_rogue")
local skillPool = self.battleData:getSkillPool()
local map = {}
local count = 0
local newSkillPool = {}
local skillWeight = {}
for _, skillId in ipairs(skillPool) do
local skillCfg = cfg[skillId]
if skillCfg and (not skillCfg.limit_times or self.battleData:getSkillCount(skillId) < skillCfg.limit_times) then
if not map[skillId] then
table.insert(newSkillPool, skillId)
table.insert(skillWeight, skillCfg.weight)
count = count + 1
map[skillId] = true
end
end
end
if count > 0 then
local index = GFunc.getRandomIndex(skillWeight)
local skillId = table.remove(newSkillPool, index)
table.remove(skillWeight, index)
count = count - 1
table.insert(result, skillId)
getCount = getCount - 1
end
for skillId, info in pairs(cfg) do
if not self:getNotInvolvedSkills()[skillId] then
if info.universal then
if not info.limit_times or self.battleData:getSkillCount(skillId) < info.limit_times then
if not map[skillId] then
table.insert(newSkillPool, skillId)
table.insert(skillWeight, info.weight)
count = count + 1
end
end
end
end
end
for i = 1, getCount do
local index = GFunc.getRandomIndex(skillWeight)
local skillId = table.remove(newSkillPool, index)
table.remove(skillWeight, index)
count = count - 1
table.insert(result, skillId)
end
result = table.shuffle(result)
return result
end
function BattleController:onSelectSkill(skillId)
self.battleData:addSkillCount(skillId)
BATTLE_ROGUE_SKILL_HANDLE.takeEffect(skillId, self.battleData, self)
local skillEntities = self.battleData:getSkillEntities()
for _, entity in pairs(skillEntities) do
entity:gotUpSKill(skillId)
end
if self.battleData:useAddlvCount() then
ModuleManager.BattleManager:showSelectSkillUI(self:getRandomSkillList())
else
self:enterRoundBegin()
end
if self.battleUI then
self.battleUI:refreshBoard()
self.battleUI:refreshSkill()
end
end
function BattleController:changeElementType(count, elementType)
local list = {}
for _, entity in pairs(self.battleData:getGridEnties()) do
if entity:canChangeInfo() and entity:getElementType() ~= elementType then
table.insert(list, entity)
end
end
for i = 1, count do
if not list[1] then
break
end
local entity = table.remove(list, math.random(1, #list))
if entity then
entity:setElementType(elementType)
end
end
end
function BattleController:addHeroAttr(attrName, value)
Logger.logHighlight("------addHeroAttr------ " .. attrName .. " " .. value)
Logger.logHighlight(self.battleData.atkTeam == nil)
if not self.battleData or not self.battleData.atkTeam then
return
end
local attr = BUFF_NAME_TO_ATTR[attrName]
if attr then
self.battleData.atkTeam:addAttr(attr[1], value, attr[2])
else
local func = BattleBuffHandle.addAttribute[attrName]
if func then
local unitComp
for matchType, comp in pairs(self.atkTeam:getUnitComp()) do
unitComp = comp
break
end
if unitComp then
func(unitComp, value)
end
end
end
end
---- 快照一次棋盘
function BattleController:snapshotBoard()
local snapshot = {}
for _, entity in pairs(self.battleData:getGridEnties()) do
snapshot[entity:getPosId()] = entity:getSnapshoptInfo()
end
return snapshot
end
function BattleController:findAttention()
local find = false
local posIdMap = {}
local pathList
for r = 1, GConst.BattleConst.ROW_COUNT do
for c = 1, GConst.BattleConst.COLUMN_COUNT do
local posId = ModuleManager.BattleManager:getPosId(r, c)
local gridEntity = self.battleData:getGridEntity(posId)
local skillId = gridEntity:getSkillId()
local mainElementType = gridEntity:getElementType()
if skillId then
local skillEntity = self.battleData:getSkillEntityBySkillId(skillId)
if skillEntity:ignoreElementType() then
mainElementType = nil
end
end
pathList = {}
self:findLinkLine(posId, posIdMap, mainElementType == nil, mainElementType, pathList)
if table.nums(pathList) >= self:getMinEliminationCount() then
find = true
break
end
end
if find then
break
end
end
return find, pathList
end
function BattleController:findLinkLine(posId, posIdMap, hadSkill, mainElementType, lineList)
posIdMap[posId] = true
table.insert(lineList, posId)
local list = BattleConst.GRID_OUT_LINE_POS_ID[posId]
if not list then
return hadSkill
end
local lineCount = 0
local maxLineList
local maxPosIdMap
local maxGotSkill
for aroundposId, _ in pairs(list) do
if not posIdMap[aroundposId] then
local gridEntity = self.battleData:getGridEntity(aroundposId)
if gridEntity then
if gridEntity:isEmptyIdle() then
if not mainElementType or gridEntity:getElementType() == mainElementType then
mainElementType = mainElementType or gridEntity:getElementType()
local tempIdMap = GFunc.getTable(posIdMap)
local newList = GFunc.getTable(lineList)
local gotSkill = self:findLinkLine(aroundposId, tempIdMap, hadSkill, mainElementType, newList)
local count = #newList
if count > lineCount then
lineCount = count
maxLineList = newList
maxPosIdMap = tempIdMap
maxGotSkill = gotSkill
end
end
elseif gridEntity:getSkillId() and not hadSkill and mainElementType then
local skillId = gridEntity:getSkillId()
local skillEntity = self.battleData:getSkillEntityBySkillId(skillId)
if skillEntity then
if skillEntity:ignoreElementType() or skillEntity:getPosition() == mainElementType then
local tempIdMap = GFunc.getTable(posIdMap)
local newList = GFunc.getTable(lineList)
local gotSkill = self:findLinkLine(aroundposId, tempIdMap, true, mainElementType, newList)
local count = #newList
if count > lineCount then
lineCount = count
maxLineList = newList
maxPosIdMap = tempIdMap
maxGotSkill = gotSkill
end
end
end
end
end
end
end
if lineCount > 0 then
for index, id in ipairs(maxLineList) do
lineList[index] = id
end
for _, id in pairs(maxPosIdMap) do
posIdMap[id] = true
end
hadSkill = maxGotSkill
end
return hadSkill
end
function BattleController:randomDisruptionBoard()
end
function BattleController:addBattleExp(exp)
if not self.battleData or not exp then
return
end
self.battleData:addExp(exp)
end
function BattleController:_tick(dt)
if self.isPause then
return
end
self.time = self.time + dt
self.atkTeam:tick(dt)
self.defTeam:tick(dt)
local count = #self.effectTexts
for i = count, 1, -1 do
self.effectTexts[i]:tick(dt)
if self.effectTexts[i]:getDuration() < 0 then
BattleHelper:recycleEffectText(self.effectTexts[i])
table.remove(self.effectTexts, i)
end
end
self:tick(dt)
end
function BattleController:battleEnd()
if self.battleUI then
self.battleUI:enableUITouch()
end
self:controllBattleEnd()
end
function BattleController:clear()
if self.alreadyClear then
return
end
self.alreadyClear = true
if self.tickSid then
BattleScheduler:unscheduleGlobal(self.tickSid)
self.tickSid = nil
end
BattleScheduler:clear()
BattleHelper:clear()
BattlePassive:clear()
self:unBindAll()
DataManager.BattleData:resetTimeSpeed()
end
function BattleController:endBattleAndExit()
ModuleManager.BattleManager:exitBattle()
end
function BattleController:showEffectNumber(num, x, y)
local effectTextComp = BattleHelper:getEffectText(self.battleUI:getNumberNode())
effectTextComp:showEffectNumber(num, x, y)
table.insert(self.effectTexts, effectTextComp)
end
local function _addCurRoundAttr(self, instruction, callback)
if instruction.effectList then
local defComp = self:getOtherSideMainUnit(BattleConst.SIDE_ATK)
local mainComp = self:getOtherSideMainUnit(BattleConst.SIDE_DEF)
for _, effect in ipairs(instruction.effectList) do
local target
if effect:getTartgetSide() == BattleConst.SIDE_DEF then
target = defComp
else
target = mainComp
end
mainComp:takeEffect(effect, target)
end
end
callback()
end
local function _assisting(self, instruction, callback)
self.atkTeam:useAssistingSkill(instruction.assistingList, callback)
end
local function _generalAttack(self, instruction, callback)
self.atkTeam:useNormalSkill(instruction.skillMatch, instruction.count, callback)
end
local function _playSkill(self, instruction, callback)
self.atkTeam:useSkill(instruction.skillMatch, instruction.count, callback)
end
BattleController._doInstruction = {
[BattleConst.INSTRUCTION_NAME.ADD_CUR_ROUND_ATTR] = _addCurRoundAttr,
[BattleConst.INSTRUCTION_NAME.ASSISTING] = _assisting,
[BattleConst.INSTRUCTION_NAME.GENERAL_ATTACK] = _generalAttack,
[BattleConst.INSTRUCTION_NAME.PLAY_SKILL] = _playSkill,
}
return BattleController