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:initBattleTeam() self:initOther() self:prepareFight() end function BattleController:initBattleTeam() self.atkTeam = BattleTeam:create() self.atkTeam:init(BattleConst.SIDE_ATK) self.defTeam = BattleTeam:create() self.defTeam:init(BattleConst.SIDE_DEF) 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 ---- 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 -- 其他的buff 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() 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) if self.battleData:useAddlvCount() then ModuleManager.BattleManager:showSelectSkillUI(self:getRandomSkillList()) else self:enterRoundBegin() end if self.battleUI then self.battleUI:refreshBoard() 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:addSkillEffect(elementType, effects) Logger.logHighlight("------addSkillEffect------ " .. elementType .. " " .. json.encode(effects)) 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: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() 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