local BattleScheduler = require "app/module/battle/helper/battle_scheduler" local BattlePassive = require "app/module/battle/helper/battle_passive" local BattlePool = require "app/module/battle/helper/battle_pool" local BattleHelper = require "app/module/battle/helper/battle_helper" local BattleBuffEntity = require "app/userdata/battle/skill/battle_buff_entity" local BattleTeam = require "app/module/battle/team/battle_team" 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 BATTLE_GRID_EFFECT_HANDLE = require "app/module/battle/skill/battle_grid_effect_handle" local BATTLE_INSTRUCTIONS_HELPER = require "app/module/battle/helper/battle_instructions_helper" local BattleBoardTouchHelper = require "app/module/battle/helper/battle_board_touch_helper" local BattleBuffHandle = require "app/module/battle/helper/battle_buff_handle" local BATTLE_SNAPSHOT_HELPER = require "app/module/battle/helper/battle_snapshot_helper" local BOARD_HELER = require "app/module/battle/helper/board_helper" local BattleFormula = require "app/module/battle/helper/battle_formula" local BattleBaseController = class("BattleBaseController") local BattleConst = GConst.BattleConst local BUFF_NAME_TO_ATTR = BattleConst.BUFF_NAME_TO_ATTR local GRID_BREAK_CONDITION = BattleConst.GRID_BREAK_CONDITION local SIDE_ATK = BattleConst.SIDE_ATK local SIDE_DEF = BattleConst.SIDE_DEF function BattleBaseController:getPosInfo(posId) return ModuleManager.BattleManager:getPosInfo(posId, self:getRowCount()) end function BattleBaseController:getRowCount() return self.battleData:getRowCount() end function BattleBaseController:getSkillEntityBySkillId(skillId) return self.battleData:getSkillEntityBySkillId(skillId, self.curActionSide) end function BattleBaseController:getSkillEntityByElement(elementType) return self.battleData:getSkillEntityByElement(elementType, self.curActionSide) end function BattleBaseController:isUnlockedSkillElementType(elementType) return self.battleData:isUnlockedSkillElementType(elementType, self.curActionSide) end function BattleBaseController:getSkillCount(skillId) return self.battleData:getSkillCount(skillId, self.curActionSide) end function BattleBaseController:getSkillPool() return self.battleData:getSkillPool(self.curActionSide) end function BattleBaseController:getSkillEntities(side) side = side or self.curActionSide return self.battleData:getSkillEntities(side) end function BattleBaseController:addSkillEnergy(elementMap, side) side = side or self.curActionSide self.battleData:addSkillEnergy(elementMap, side) end -- *************各个子模块的战斗需要重写的方法 START************* function BattleBaseController:getBoardConfig() return {} end function BattleBaseController:getChapterConfig() return {} end function BattleBaseController:getChapterId() return 0 end function BattleBaseController:getBuffs() return {} end function BattleBaseController:getBattleUIPath() return "app/ui/battle/battle_ui" end ---- 障碍格子图片 function BattleBaseController:getBlockIcon() local chapterInfo = self:getChapterConfig()[self.chapterId] if not chapterInfo then return "battle_hinder_4" end return chapterInfo.block_icon end function BattleBaseController:getChessBoardBgName() local chapterInfo = self:getChapterConfig()[self.chapterId] if not chapterInfo then return "chessboard_1" end return chapterInfo.chess_board end function BattleBaseController:getScene() local chapterInfo = self:getChapterConfig()[self.chapterId] if not chapterInfo then return "bg_1" end return chapterInfo.scene end function BattleBaseController:refreshWave() if not self.battleUI then return end self.battleUI:refreshWave(self:getWaveIndex()) end -- 战斗结束 function BattleBaseController:controllBattleEnd() end -- 不同模块的战斗需要初始化的东西 function BattleBaseController:initOther() end -- 怪物攻击力加成 function BattleBaseController:getMonsterAtkAddition() return 0 end -- 怪物血量加成 function BattleBaseController:getMonsterHpAddition() return 0 end -- 怪物攻击力固定 function BattleBaseController:getMonsterAtkFixed() return 0 end -- 怪物血量固定 function BattleBaseController:getMonsterHpFixed() return 0 end -- 需要额外加载的资源 function BattleBaseController:loadOtherRes(callback) return callback() end function BattleBaseController:tick(dt) end -- 一共有多少波 function BattleBaseController:getMaxWave() local config = self:getChapterConfig()[self.chapterId] if not config or not config.monster then return 0 end return #config.monster end function BattleBaseController:getMinEliminationCount() if not self.minEliminationCount then self.minEliminationCount = GFunc.getConstIntValue("element_combo") end return self.minEliminationCount end function BattleBaseController:getNextMonsterId(waveIndex) waveIndex = waveIndex or self:getWaveIndex() + 1 local config = self:getChapterConfig()[self.chapterId] local monsterId = config.monster[waveIndex] return monsterId end function BattleBaseController:showBossEnterAni(bornTime, bossName, monsterComp, callback) self.battleUI:showBossEnterAni(bornTime, bossName, monsterComp, callback) end function BattleBaseController:generateNextMonster() local monsterId = self:getNextMonsterId() if monsterId == nil then return self:enterNextWave() end local isBoss = self.defTeam:getIsBoss() local unitEntity = self.battleData:addMonster(monsterId, true, self) local modelId = unitEntity:getModelId() BattleHelper:loadBattleHeroModel(modelId, self.battleUI:getBattleNode(), function(spineObject) self.defTeam:removeAllUnits() local monsterComp = spineObject:addLuaComponent(GConst.BattleConst.TYPEOF_LUA_COMP.BATTLE_MONSTER_COMPONENT) monsterComp:initWithEntity(modelId, unitEntity, self) self.defTeam:addUnit(monsterComp, true) self:handleBuffs(GConst.BattleConst.SIDE_DEF) self.battleUI:refreshDefHp(unitEntity:getHp(), unitEntity:getHpPercent()) local bornTime = monsterComp:getAnimationDuration(GConst.BattleConst.SPINE_ANIMATION_NAME.BORN) if isBoss then -- 如果是boss就跑过去 local count = 0 local function onFinish() count = count + 1 if count == 2 then self.atkTeam:stopRunAction() self:onRoundEnd(true) end end self.atkTeam:playRunAction() self.atkTeam:recoverHpOnWaveOver(onFinish) isBoss = self.defTeam:getIsBoss() if isBoss then local monsterInfo = ConfigManager:getConfig("monster")[monsterId] self:showBossEnterAni(bornTime, ModuleManager.HeroManager:getMonsterName(monsterInfo.monster_base), monsterComp, function() monsterComp:playEnterBattlefield(true, onFinish) end) else monsterComp:playEnterBattlefield(true, onFinish) end else local count = 0 local function onFinish() count = count + 1 if count == 2 then self:onRoundEnd(true) end end self.atkTeam:recoverHpOnWaveOver(onFinish) isBoss = self.defTeam:getIsBoss() if isBoss then local monsterInfo = ConfigManager:getConfig("monster")[monsterId] self:showBossEnterAni(bornTime, ModuleManager.HeroManager:getMonsterName(monsterInfo.monster_base), monsterComp, function() monsterComp:playEnterBattlefield(false, onFinish) end) else monsterComp:playEnterBattlefield(false, onFinish) end end end) end function BattleBaseController:findNextDefUnit() self:generateNextMonster() end function BattleBaseController:onDefDead(callback) self.defTeam:getMainUnit():playDead(function() local monsterId = self.defTeam:getMainUnit().unitEntity:getDeathSummon() if monsterId > 0 then self:generateMonsterById(monsterId, function() self.curWaveMonsterDead = false if callback then callback() end self:handleBuffs(BattleConst.SIDE_DEF) end) else if callback then callback() end end end) end function BattleBaseController:onLinkChange() self.battleUI:hideAllSfxLine() self.linkChangeNeedFalsePosMap = table.clearOrCreate(self.linkChangeNeedFalsePosMap) for posId, entity in pairs(self.battleData:getGridEnties()) do if entity:getCell() then self.linkChangeNeedFalsePosMap[posId] = entity:getCell() end end local sequence = self.battleData:getGridSequence() local mainElementType local dmgSkillId for index, info in ipairs(sequence) do local entity = self.battleData:getGridEntity(info.posId) if not mainElementType or not dmgSkillId then local skillId = entity:getSkillId() if not skillId and not mainElementType then mainElementType = entity:getElementType() end if skillId and not dmgSkillId then dmgSkillId = skillId end if mainElementType and dmgSkillId then break end end end local count = #sequence for index, info in ipairs(sequence) do local entity = self.battleData:getGridEntity(info.posId) if entity:getCell() then entity:getCell():showHighLight(true, mainElementType, self.battleUI) end if self.linkChangeNeedFalsePosMap[info.posId] then self.linkChangeNeedFalsePosMap[info.posId] = nil end if index < count then local nextPosId = sequence[index + 1].posId self.battleUI:getSfxLine(index, function(obj) local curPos = self:getPosInfo(info.posId) local nextPos = self:getPosInfo(nextPosId) local pos, z = ModuleManager.BattleManager:getPosCenterAndDir(curPos, nextPos) obj:setLocalScale(25, 25, 25) obj:setLocalPosition(pos.x, pos.y, 0) obj:setEulerAngles(0, 0, z) end) end if index == count then if entity:getCell() then entity:getCell():showAni() end end end for posId, cell in pairs(self.linkChangeNeedFalsePosMap) do cell:showHighLight(false) end self.teampSkillBreakEnergyMap = table.clearOrCreate(self.teampSkillBreakEnergyMap) for posId, info in pairs(self.battleData:getSkillInfluenceGrids()) do local entity = self.battleData:getGridEntity(posId) if info.direction ~= BattleConst.BOARD_RANGE_TYPE.RANDOM then if entity:getCell() then entity:getCell():showCircle(true) if dmgSkillId then local skillEntity = self.battleData:getSkillEntityBySkillId(dmgSkillId) local multiple = skillEntity and skillEntity:getSkillBreakEnergyMultiple() or 1 if multiple > 1 then entity:getCell():setCountStr(skillEntity:getSkillBreakEnergyMultipleStr()) local elementType = entity:getElementType() if entity:canLink() and elementType and elementType > 0 then self.teampSkillBreakEnergyMap[elementType] = (self.teampSkillBreakEnergyMap[elementType] or 0) + (multiple - 1) end end end end end end local dmgElementTypeMap if not self:getCurActionUnitComp():getActiveSkillLimit() then local aniSequence, influenceElementType, lineCount, elementTypeMap, linkElementType, effectGridMap, randomPosList = self:calculateCurElimination(true) dmgElementTypeMap = elementTypeMap if randomPosList then for _, posId in ipairs(randomPosList) do local gridEntity = self.battleData:getGridEntity(posId) if gridEntity and gridEntity:canLink() then local elementType = gridEntity:getElementType() if elementTypeMap[elementType] and elementTypeMap[elementType] > 0 then elementTypeMap[elementType] = elementTypeMap[elementType] - 1 end end end end for elementType, count in pairs(elementTypeMap) do self.teampSkillBreakEnergyMap[elementType] = (self.teampSkillBreakEnergyMap[elementType] or 0) + count end self.battleUI:refreshSkill(elementTypeMap, count > 0, self.curActionSide) end if mainElementType then self:getSideTeam(self.curActionSide):changeMainUnit(mainElementType) end local elementTypeCount = 0 if dmgElementTypeMap then for element, count in pairs(dmgElementTypeMap) do elementTypeCount = elementTypeCount + count end end local dmg = self:calExpectedInjury(mainElementType, elementTypeCount, dmgSkillId) local defMainUnitcomp = self:getCurOtherActionUnitComp() if defMainUnitcomp then local hp = defMainUnitcomp.unitEntity:getHp() local hpPercent = (hp - dmg) / defMainUnitcomp.unitEntity:getMaxHp() if self.curActionSide == SIDE_ATK then self.battleUI:setDefHp(hp, hpPercent) else self.battleUI:setAtkHp(hp, hpPercent) end end end function BattleBaseController:getInitBoard() if not self.boradList then self.boradList = {} self.fixedRandomGrid = {} self.mysteryBoxIndexMap = {} local config = self:getChapterConfig()[self.chapterId] local boardCfg = self:getBoardConfig() for _, boardId in ipairs(config.board) do local cfg = boardCfg[boardId] if cfg then table.insert(self.boradList, {board = GFunc.getTable(cfg.board), mysteryBoard = GFunc.getTable(cfg.mystery_box_board), gridEdge = GFunc.getTable(cfg.grid_edge)}) table.insert(self.fixedRandomGrid, GFunc.getTable(cfg.control_element)) end end end return self.boradList, self.fixedRandomGrid, self.mysteryBoxIndexMap end function BattleBaseController:getNotInvolvedSkills() if not self.notInvolvedSkills then self.notInvolvedSkills = {} local config = self:getChapterConfig()[self.chapterId] if config.not_involved_skill then for _, skillId in ipairs(config.not_involved_skill) do self.notInvolvedSkills[skillId] = true end end end return self.notInvolvedSkills end function BattleBaseController:getFixedRogueSkill() if not self.fixedRogueSkill then self.fixedRogueSkill = {} end return self.fixedRogueSkill end function BattleBaseController:getSealElementType() if not self.sealElementType then self.sealElementType = {} local config = self:getChapterConfig()[self.chapterId] if config.seal_element then for _, elementType in ipairs(config.seal_element) do self.sealElementType[elementType] = true end end end return self.sealElementType end function BattleBaseController:getAtkMinRow() return 0 end -- *************各个子模块的战斗需要重写的方法 end************* function BattleBaseController:handleBuffs(side) for _, buffInfo in ipairs(self:getBuffs()) do local buffEntity = buffInfo.buffEntity local buffTargetSide = buffEntity:getTargetSide() local target if buffTargetSide == BattleConst.SIDE_DEF then target = self.defTeam:getMainUnit() elseif buffTargetSide == BattleConst.SIDE_ATK then target = self.atkTeam:getMainUnit() elseif buffTargetSide == BattleConst.SIDE_ATK_ALL then if not side or side == buffTargetSide then for matchtype, comp in pairs(self.atkTeam:getUnitComp()) do local buffEntity = BattleBuffEntity:create() buffEntity:init(buffInfo.effect, comp.unitEntity) buffEntity:setTargetSide(buffTargetSide) comp:takeEffect(buffEntity, comp) end end else local matchType = BattleConst.SIDE_OBJ_TO_MATCH_TYPE[buffTargetSide] if matchType then target = self.atkTeam:getUnitComp()[matchType] end end if target then if side then if buffTargetSide == side then buffEntity:setOwner(target) target:takeEffect(buffEntity, target) end else buffEntity:setOwner(target) target:takeEffect(buffEntity, target) end end end end function BattleBaseController:ctor() self.battleData = DataManager.BattleData end function BattleBaseController:init(params, snapshot) params = params or {} self.snapshot = snapshot self.params = params self.battleType = params.battleType or GConst.BattleConst.BATTLE_TYPE.STAGE self.waveDurationTime = 0 self.totalDurationTime = 0 self.eliminateCount = 0 self.eliminateTotalCount = 0 self.maxLinkCount = 0 self.realTime = 0 self.taskProgress = {} self.waveRoundCount = {} self.lastRoundBreakedGridType = {} self.waitingFillCount = 0 self.needWaitingBoardOver = nil self.curWaveMonsterDead = false self.totalBreakedGridType = {} self.totalEliminateCountMap = {} self.curActionSide = SIDE_ATK self:resetSideActionCount() 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.gotMysteryBoxIndexs = {} self.showMysteryBoxIndexs = {} self.delayEffectTextList = {} self.delayEffectTextCount = 0 self.time = 0 self.battleData:setTimeScaleBase(nil) -- 还原 if snapshot then -- 处理战斗快照 self:dealSnapshotBattleBaseInfo(snapshot) self.battleData:init(params, snapshot.battledataShopInfo) else self.battleData:init(params) end BattleScheduler:init() BattlePool:init() BattleHelper:init() BattlePassive:init() self:setTimeScale(self.battleData:getTimeScale()) self:bindData() self:initBattleTeam() self:initOther() self:prepareFight() end function BattleBaseController:dealSnapshotBattleExtraInfo(snapshot) BATTLE_SNAPSHOT_HELPER:dealSnapshotBattleExtraInfo(self, snapshot) end function BattleBaseController:dealSnapshotBattleBaseInfo(snapInfo) BATTLE_SNAPSHOT_HELPER:dealSnapshotBattleBaseInfo(self, snapInfo) end function BattleBaseController:snapshotBattleInfo() BATTLE_SNAPSHOT_HELPER:snapshotBattleInfo(self) end function BattleBaseController:bindData() self.battleData:bind("timeSpeed", ModuleManager.BattleManager, function() self:setTimeScale( self.battleData:getTimeScale()) end, false) end function BattleBaseController:unBindAll() self.battleData:unBind("timeSpeed", ModuleManager.BattleManager) end function BattleBaseController: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 BattleBaseController:resetSideActionCount() if not self.sideActionCount then self.sideActionCount = { [SIDE_ATK] = 1, [SIDE_DEF] = 1, } else self.sideActionCount[SIDE_ATK] = 1 self.sideActionCount[SIDE_DEF] = 1 end end function BattleBaseController:resduceSideActionCount(side) if not self.sideActionCount or not self.sideActionCount[side] then return false end if self.sideActionCount[side] > 0 then self.sideActionCount[side] = self.sideActionCount[side] - 1 return true else return false end end function BattleBaseController:getSideActionCount(side) if not self.sideActionCount or not self.sideActionCount[side] then return 0 end return self.sideActionCount[side] end function BattleBaseController:getControllerParams() return self.params end function BattleBaseController:setCurActionSide(side) self.curActionSide = side or SIDE_ATK end function BattleBaseController:setIsPauseHpProgress(value) self.battleUI:setIsPauseHpProgress(value) end function BattleBaseController:getIsPvpBattle() return BattleConst.IS_PVP_BATTLE[self.battleType] == true end function BattleBaseController:moveBattlefield(time) self.battleUI:moveBattlefield(time) end function BattleBaseController:refreshBuff(side, buffList) self.battleUI:refreshBuff(side, buffList) end function BattleBaseController:clearBuff(side) self.battleUI:clearBuff(side) end function BattleBaseController:showBuffTips(side, autoClose) if side == BattleConst.SIDE_ATK then local buffList = self.atkTeam:getBuffList() if #buffList <= 0 then return end self.battleUI:showLeftBuffTips(buffList, autoClose) else local buffList = self.defTeam:getBuffList() if #buffList <= 0 then return end self.battleUI:showRightBuffTips(buffList, autoClose) end end function BattleBaseController:showCombo(count, side) self.battleUI:showCombo(count, side) end function BattleBaseController:hideCombo() self.battleUI:hideCombo() end function BattleBaseController:showCounterAttack(count, side) self.battleUI:showCounterAttack(count, side) end function BattleBaseController:hideCounterAttack() self.battleUI:hideCounterAttack() end function BattleBaseController: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(), {battleController = self}) self.battleUI:addLoadUICompleteListener(function() BattleHelper:setEffectTextCache(self.battleUI:getBattleNumberRed(), self.battleUI:getBattleNumberGreen(), self.battleUI:getBattleNumberBlue(), self.battleUI:getBattleNumberWhite(), self.battleUI:getBattleNumberSpecial()) self:initAtkUnits(onPreloadFinished) self:initDefUnits(onPreloadFinished) self.battleUI:refreshChessBoard(self:getChessBoardBgName()) self.battleUI:loadBg(self:getScene()) end) BattleHelper:setBaseOrder(self.battleUI:getUIOrder()) BattleHelper:setBattleData(self.battleData) BattleBoardTouchHelper:init(self) self:loadOtherRes(onPreloadFinished) end function BattleBaseController: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 BattleBaseController:initDefUnits(callback) local initIndex = self:getWaveIndex() if initIndex <= 0 then initIndex = 1 end local monsterId = self:getNextMonsterId(initIndex) local unitEntity = self.battleData:addMonster(monsterId, nil, self) local modelId = unitEntity:getModelId() BattleHelper:loadBattleHeroModel(modelId, self.battleUI:getBattleNode(), function(spineObject) local monsterComp = spineObject:addLuaComponent(BattleConst.TYPEOF_LUA_COMP.BATTLE_MONSTER_COMPONENT) monsterComp:initWithEntity(modelId, unitEntity, self) self.defTeam:addUnit(monsterComp, true) self.battleUI:refreshDefHp(unitEntity:getHp(), unitEntity:getHpPercent()) callback() end) end function BattleBaseController:refreshHp(side, num, percent) if side == BattleConst.SIDE_ATK then self.battleUI:refreshAtkHp(num, percent) else self.battleUI:refreshDefHp(num, percent) end end function BattleBaseController:getOtherSideMainUnit(side) if side == BattleConst.SIDE_ATK then return self.defTeam:getMainUnit() else return self.atkTeam:getMainUnit() end end function BattleBaseController:getOtherSideTeam(side) if side == BattleConst.SIDE_ATK then return self.defTeam else return self.atkTeam end end function BattleBaseController:getSideTeam(side) if side == BattleConst.SIDE_ATK then return self.atkTeam else return self.defTeam end end function BattleBaseController:getCurActionTeam(side) side = side or self.curActionSide local isAtkAction = side == SIDE_ATK local team = isAtkAction and self.atkTeam or self.defTeam return team end function BattleBaseController:getCurActionSide() return self.curActionSide end function BattleBaseController:getCurActionOtherSide() if self.curActionSide == SIDE_ATK then return SIDE_DEF else return SIDE_ATK end end function BattleBaseController:getCurActionUnitComp() return self:getCurActionTeam():getMainUnit() end function BattleBaseController:getCurOtherActionUnitComp() local side = self:getCurActionOtherSide() if not side then return end local team = self:getCurActionTeam(side) if not team then return end return team:getMainUnit() end function BattleBaseController:getCurActionBoardRowRange(side) side = side or self.curActionSide local isAtkAction = side == SIDE_ATK if isAtkAction then return self:getAtkMinRow() + 1, self:getRowCount() else return 1, self:getAtkMinRow() end end function BattleBaseController:getPosIdInCurActionBoardRowRange(posId) local min, max = self:getCurActionBoardRowRange() local r = ModuleManager.BattleManager:getPosRC(posId).r if r < min or r > max then return false end return true end function BattleBaseController:getPosIdInActionBoardRowRange(side, posId) local min, max = self:getCurActionBoardRowRange(side) local r = ModuleManager.BattleManager:getPosRC(posId).r if r < min or r > max then return false end return true end function BattleBaseController:onLoadComplete() UIManager:closeLoading() self:handleBuffs() if self.snapshot then self:dealSnapshotBattleExtraInfo(self.snapshot) end self:battleStart() end function BattleBaseController:battleStart() self.atkTeam:prepare() self.defTeam:prepare() self.isBattleStart = true self.tickSid = BattleScheduler:scheduleGlobal(function(dt, originDt) self:_tick(dt, originDt) end, 0) if self.snapshot then self:enterNextWaveBySnapshot(self.snapshot) else self:enterNextWave() end end function BattleBaseController:addTimeSpeed() if self.skillSlowDownDuration then return end self.battleData:addTimeSpeed() end function BattleBaseController:resetTimeSpeed(isDeadReset) if isDeadReset then if self.skillSlowDownDuration then return end end self.battleData:resetTimeSpeed() if self.skillSlowDownDuration then self.skillSlowDownDuration = nil end end function BattleBaseController:setSkillSlowDown(timeScale, duration) self.skillSlowDownDuration = duration self.battleData:setSkillTimeSpeed(timeScale) end function BattleBaseController:setTimeScale(timeScale) GFunc.setDOTweenTimeScale(GConst.DOTWEEN_IDS.BATTLE, timeScale) BattleScheduler:setTimeScale(timeScale) BattleHelper:setTimeScale(timeScale) end function BattleBaseController:addWaveIndex(wave) local origin = self:getWaveIndex() self.waveIndex = GFunc.encryptNumber(origin + wave) end function BattleBaseController:setWaveIndex(wave) self.waveIndex = GFunc.encryptNumber(wave) end function BattleBaseController:getWaveIndex() if self.waveIndex <= 0 then return 0 end return GFunc.decryptNumber(self.waveIndex) end function BattleBaseController:_findNextDefUnit() if self.isBossWave then -- 如果上一波是boss波次,则重新生成棋盘 self:putBoardCacheSkill(function() self.atkTeam:onRoundEnd() self:findNextDefUnit() self:generateBoard() end) else self.atkTeam:onRoundEnd() self:findNextDefUnit() end end ---- start 回合步骤 function BattleBaseController:enterNextWave() local waveIndex = self:getWaveIndex() if waveIndex ~= 0 and self.curWaveMonsterDead then if self.isBossWave then self:addTaskProgress(BattleConst.BATTLE_TASK_FIELD.KILL_BOSS, 1) else self:addTaskProgress(BattleConst.BATTLE_TASK_FIELD.KILL_NORMAL_MONSTER, 1) end self:setTaskProgress(BattleConst.BATTLE_TASK_FIELD.PASS_WAVE, waveIndex) end if waveIndex >= self.maxWaveIndex then self.victory = self.curWaveMonsterDead self:postWaveOver(not self.curWaveMonsterDead) self:battleEnd() return end local atkTeam = self.battleData:getAtkTeam() if not atkTeam or atkTeam:getIsDead() then self.victory = false self:postWaveOver(true) self:battleEnd() return end if waveIndex ~= 0 then -- 第一波 self:postWaveOver(false) end self.curWaveMonsterDead = false self:addWaveIndex(1) waveIndex = self:getWaveIndex() self:refreshWave(waveIndex) if waveIndex == 1 then -- 第一波 self.needWaitingBoardOver = true self:generateBoard(true) else -- 上报关卡结束 self.defTeam:prepare() end self.waveDurationTime = 0 self.eliminateCount = 0 self:snapshotBattleInfo() self.isBossWave = self.defTeam:getMainUnit().unitEntity:getIsBoss() self:postFightStart() if not self.needWaitingBoardOver then self:enterRoundBegin() end if not self.isBossWave then self.battleUI:hideBuffTips() end end function BattleBaseController:enterNextWaveBySnapshot(snapShot) local atkTeam = self.battleData:getAtkTeam() if not atkTeam or atkTeam:getIsDead() then self.victory = false self:battleEnd() return end self.curWaveMonsterDead = false self:refreshWave(self:getWaveIndex()) self.needWaitingBoardOver = true self:generateBoard(true, snapShot) self.waveDurationTime = 0 self.eliminateCount = 0 self:snapshotBattleInfo() self.isBossWave = self.defTeam:getMainUnit().unitEntity:getIsBoss() self:postFightStart() if not self.needWaitingBoardOver then self:enterRoundBegin() end if not self.isBossWave then self.battleUI:hideBuffTips() end end function BattleBaseController:enterRoundBegin() self.battleData:clearBreakGridEdgeTag() self:hideTouchCancel() self:resetSideActionCount() self:setCurActionSide(SIDE_ATK) self.needWaitingBoardOver = nil local waveIndex = self:getWaveIndex() self.waveRoundCount[waveIndex] = (self.waveRoundCount[waveIndex] or 0) + 1 self.battleUI:enterShowBoardAni(function() self:enterEliminationBegin() end) table.clear(self.lastRoundBreakedGridType) end function BattleBaseController:takeGridEffect() local haveGridEffectSucc = false local gridEntities = self.battleData:getGridEnties() local effectGrid = {} for posId, entity in pairs(gridEntities) do if entity:getEffectType() then table.insert(effectGrid, entity) end end effectGrid = table.shuffle(effectGrid) local availableEffectTypeMap for _, entity in ipairs(effectGrid) do local effectType = entity:getEffectType() if effectType ~= BattleConst.GRID_EFFECT_TYPE.CROSS_MOVE_NOT_BREAK and (not availableEffectTypeMap or not availableEffectTypeMap[effectType]) then local succ = BATTLE_GRID_EFFECT_HANDLE.gridEffectOn(entity:getPosId(), gridEntities, BattleConst.GRID_EFFECT_TRIGGER_TYPE.ON_ROUND_BEGIN, self) if succ and (effectType == BattleConst.GRID_EFFECT_TYPE.CROSS_SPREAD or effectType == BattleConst.GRID_EFFECT_TYPE.CROSS_SPREAD_NOT_BREAK) then if not availableEffectTypeMap then availableEffectTypeMap = {} end availableEffectTypeMap[effectType] = true haveGridEffectSucc = succ end end end for _, entity in ipairs(effectGrid) do -- gridEffect == 6的最后处理 local effectType = entity:getEffectType() if effectType == BattleConst.GRID_EFFECT_TYPE.CROSS_MOVE_NOT_BREAK and (not availableEffectTypeMap or not availableEffectTypeMap[effectType]) then local succ = BATTLE_GRID_EFFECT_HANDLE.gridEffectOn(entity:getPosId(), gridEntities, BattleConst.GRID_EFFECT_TRIGGER_TYPE.ON_ROUND_BEGIN, self) if succ then if not availableEffectTypeMap then availableEffectTypeMap = {} end availableEffectTypeMap[effectType] = true haveGridEffectSucc = succ end end end return haveGridEffectSucc end function BattleBaseController:enterEliminationBegin() self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_BEGIN self:enterRefreshBoard(true, function() local haveGridEffectSucc = self:takeGridEffect() if haveGridEffectSucc then -- 如果成功,则等待效果播放完成后,进入消除逻辑 if self.haveGridEffectSuccSid then ModuleManager.BattleManager:unscheduleGlobal(self.haveGridEffectSuccSid) self.haveGridEffectSuccSid = nil end ModuleManager.BattleManager:performWithDelayGlobal(function() self:enterElimination(true) end, 1.1) else self:enterElimination(true) end end) end function BattleBaseController:enterElimination(needDelay) if self.haveGridEffectSuccSid then ModuleManager.BattleManager:unscheduleGlobal(self.haveGridEffectSuccSid) self.haveGridEffectSuccSid = nil end if self.showSelectSkillSid then ModuleManager.BattleManager:unscheduleGlobal(self.showSelectSkillSid) self.showSelectSkillSid = nil end if self.battleData:useAddlvCount() then self:tryShowSelectSkillComp(needDelay) return end self.battleUI:hideAllBoardSfxs() -- 检查棋盘 local find, pathList = self:findAttention() if not find then -- 如果没找到,就要打乱棋盘 self:shuffleBoard(function() self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_ELIMINATION end) else self.attentionList = pathList -- ModuleManager.BattleManager:performWithDelayGlobal(function() -- for _, posId in ipairs(pathList) do -- local entity = self.battleData:getGridEntity(posId) -- if entity and entity:getCell() then -- entity:getCell():showAni() -- end -- end -- end, 2) self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_ELIMINATION end end function BattleBaseController:enterBattleStep() self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_TEAM_ACTION self.battleTeamActionList = table.clearOrCreate(self.battleTeamActionList) local atkAction = function() self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_ATK_STEP self:exeInstructions(function() self:enterNextTeamAction() end, self.curActionSide) end local defAction = function() self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_DEF_STEP self.defTeam:mainUnitUseAllSkills(BattleConst.ATTACK_ACTION_STATE.NORMAL, function() self:enterNextTeamAction() end) end if self.battleData:getAtkTeam():getFirstHand() < self.battleData:getDefTeam():getFirstHand() then self:addTeamActionList(defAction, 1) self:addTeamActionList(atkAction, 2) else self:addTeamActionList(atkAction, 1) self:addTeamActionList(defAction, 2) end self:enterNextTeamAction() end function BattleBaseController:addTeamActionList(func, index) if not self.battleTeamActionList then self.battleTeamActionList = {} end index = index or 1 table.insert(self.battleTeamActionList, index, func) end function BattleBaseController:enterNextTeamAction() self.atkTeam:onActionOver() self.defTeam:onActionOver() self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_TEAM_ACTION_OVER self:hideCombo() self:hideCounterAttack() self:checkTeamIsDead(function() self:enterRoundEnd() end, function() if not self.battleTeamActionList or not self.battleTeamActionList[1] then self:enterRoundEnd() return end local action = table.remove(self.battleTeamActionList, 1) action() end) end function BattleBaseController:checkTeamIsDead(callback, falseCallback) local defTeam = self.battleData:getDefTeam() local atkTeam = self.battleData:getAtkTeam() if atkTeam:getIsDead() and defTeam:getIsDead() then -- 都死了,直接结算 self.curWaveMonsterDead = true self:enterNextWave() return true end if not defTeam or defTeam:getIsDead() then -- 怪物死了, 直接进入刷新逻辑 self.curWaveMonsterDead = true self:onDefDead(function() self.defTeam:removeAllBuff() if self.battleData:getDefTeam():getIsDead() then if self:getWaveIndex() >= self.maxWaveIndex then if callback() then callback() end else self:_findNextDefUnit() end else if callback() then callback() end end end) return true end if not atkTeam or atkTeam:getIsDead() then -- 英雄死了, 直接结算 self:enterNextWave() return true end if falseCallback then falseCallback() end end function BattleBaseController:getIsAtkStep() return self.roundStep == BattleConst.BATTLE_ROUND_STEP.ON_ATK_STEP end function BattleBaseController:enterRefreshBoard(isRoundBeginCheck, callback) if not isRoundBeginCheck then self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_REFRESH_BOARD end self.onFillBoardOverCallback = callback self.isRoundBeginCheck = isRoundBeginCheck if self.isRoundBeginCheck and self.waitingFillCount > 0 then self.isWaitingFill = true return end self:fillBoard(self.isRoundBeginCheck) end function BattleBaseController:enterRoundEnd() self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_END local defTeam = self.battleData:getDefTeam() if not defTeam or defTeam:getIsDead() then -- 怪物死了, 直接进入刷新逻辑 self.curWaveMonsterDead = true 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() self:checkTeamIsDead(function() self:enterNextWave() end, function() self:onRoundEnd() end) end function BattleBaseController:onRoundEnd(toNextWave) if toNextWave then self:enterNextWave() else self:enterRoundBegin() end end ---- end回合步骤 function BattleBaseController:onTouchEvent(eventType, posId, isVirtual) BattleBoardTouchHelper:onTouchEvent(eventType, posId, isVirtual) end function BattleBaseController:showTouchCancel() self.battleUI:showTouchCancel() end function BattleBaseController:hideTouchCancel() self.battleUI:hideTouchCancel() end function BattleBaseController:clearGridSequence() self:hideTouchCancel() local sequence = self.battleData:getGridSequence() local count = #sequence if count <= 0 then self.battleData:clearGridSequence() self:onLinkChange() return end local snapshot = self.battleData:getFirstSequenceSnapshot() if snapshot then -- 如果有快照,则恢复一次 for posId, info in pairs(snapshot) do self.battleData:setInfoBySnapshop(posId, info) end end self.battleData:clearGridSequence() self:onLinkChange() end function BattleBaseController:onLinkOver() local hp = self.atkTeam:getMainUnit().unitEntity:getHp() local hpPercent = self.atkTeam:getMainUnit().unitEntity:getHpPercent() self.battleUI:setAtkHp(hp, hpPercent) local hp = self.defTeam:getMainUnit().unitEntity:getHp() local hpPercent = self.defTeam:getMainUnit().unitEntity:getHpPercent() self.battleUI:setDefHp(hp, hpPercent) self.battleUI:hideAllSfxLine() local sequence = self.battleData:getGridSequence() local count = #sequence if count < self:getMinEliminationCount() then return end local isAtkAction = self.curActionSide == SIDE_ATK local skillId = self.battleData:getSequenceHadSkill() local skillEntity if skillId then skillEntity = self:getSkillEntityBySkillId(skillId) if isAtkAction then self:addTaskProgress(BattleConst.BATTLE_TASK_FIELD.BOARD_SKILL_RELEASE_COUNT, 1) end end self.teampSkillBreakEnergyMap = table.clearOrCreate(self.teampSkillBreakEnergyMap) if skillEntity then for posId, info in pairs(self.battleData:getSkillInfluenceGrids()) do local entity = self.battleData:getGridEntity(posId) if entity then local multiple = skillEntity and skillEntity:getSkillBreakEnergyMultiple() or 1 if multiple > 1 then entity:getCell():setCountStr(skillEntity:getSkillBreakEnergyMultipleStr()) local elementType = entity:getElementType() if entity:canLink() and elementType and elementType > 0 then self.teampSkillBreakEnergyMap[elementType] = (self.teampSkillBreakEnergyMap[elementType] or 0) + (multiple - 1) end end end end end local aniSequence, influenceElementTypeMap, lineCount, elementTypeMap, linkElementType, effectGridMap = self:calculateCurElimination() if not self:getCurActionUnitComp():getActiveSkillLimit() then for elementType, count in pairs(elementTypeMap) do self.teampSkillBreakEnergyMap[elementType] = (self.teampSkillBreakEnergyMap[elementType] or 0) + count end self:addSkillEnergy(self.teampSkillBreakEnergyMap) end self.battleData:clearGridSequence() self.battleUI:disableUITouch() self.battleUI:eliminationAni(aniSequence, effectGridMap, function() self:enterRefreshBoard(nil, function() self:onLinkOverDone(skillEntity, linkElementType, lineCount, influenceElementTypeMap, elementTypeMap) end) end, self.curActionSide) for element, count in pairs(elementTypeMap) do self.totalEliminateCountMap[element] = (self.totalEliminateCountMap[element] or 0) + count end self.eliminateCount = self.eliminateCount + 1 self.eliminateTotalCount = self.eliminateTotalCount + 1 if count > self.maxLinkCount then self.maxLinkCount = count end end function BattleBaseController:onLinkOverDone(skillEntity, linkElementType, lineCount, influenceElementTypeMap, elementTypeMap) self.battleUI:enterHideBoardAni(function() self:generateInstructions(skillEntity, linkElementType, lineCount, influenceElementTypeMap, elementTypeMap) self:enterBattleStep() end) end function BattleBaseController:calculateCurElimination(onlyCheck) local sequence = self.battleData:getGridSequence() local skillId = self.battleData:getSequenceHadSkill() local skillEntity if skillId then skillEntity = self:getSkillEntityBySkillId(skillId) end self.breakedMap = table.clearOrCreate(self.breakedMap) self.boomGridIds = table.clearOrCreate(self.boomGridIds) self.sequenceMap = table.clearOrCreate(self.sequenceMap) self.aniSequence = table.clearOrCreate(self.aniSequence) for idx, info in ipairs(sequence) do self.sequenceMap[info.posId] = idx end local time = 0 local skillTime = BattleConst.SKILL_ELIMINATION_TIME for idx, info in ipairs(sequence) do local posId = info.posId self:dealGridBreak(posId, GRID_BREAK_CONDITION.LINE, time, self.breakedMap, self.sequenceMap, self.aniSequence, self.boomGridIds, onlyCheck) time = time + BattleConst.ELIMINATION_INTERVAL end local randomPosList, influenceElementTypeMap for i, info in ipairs(self.aniSequence) do if info.isSkill and skillEntity then randomPosList, influenceElementTypeMap = self:dealSkillElement(info.timeIdx + skillTime, self.breakedMap, self.sequenceMap, self.aniSequence, self.boomGridIds, onlyCheck) local aniUnit = self.aniSequence[i] if not BattleConst.NO_EFFECT_GRID_SKILL_TYPE[skillEntity:getSkillType()] then aniUnit.rangeList = skillEntity:getBoardRange() aniUnit.randomPosList = randomPosList end break end end self.elementTypeMap = table.clearOrCreate(self.elementTypeMap) self.effectGridMap = table.clearOrCreate(self.effectGridMap) local linkElementType local lineCount = 0 local gridEntities = self.battleData:getGridEnties() for _, info in ipairs(self.aniSequence) do local entity = gridEntities[info.posId] local elementType = entity:getElementType() if not info.noAni and info.isIdle then if not info.isSkill then if not entity:isElmentTypeInvalid() then self.elementTypeMap[elementType] = (self.elementTypeMap[elementType] or 0) + 1 end if self.boomGridIds[info.posId] and self.boomGridIds[info.posId][GRID_BREAK_CONDITION.LINE] then lineCount = lineCount + 1 linkElementType = elementType end end end if entity:getEffectType() and info.isIdle then self.effectGridMap[info.posId] = true end end return self.aniSequence, influenceElementTypeMap, lineCount, self.elementTypeMap, linkElementType, self.effectGridMap, randomPosList end function BattleBaseController:dealGridBreak(posId, condition, time, breakedMap, sequenceMap, aniSequence, gridMap, onlyCheck) self:setGridBreakCondition(gridMap, posId, condition) if breakedMap[posId] or (sequenceMap[posId] and condition ~= GRID_BREAK_CONDITION.LINE) then return end local gridEntities = self.battleData:getGridEnties() local entity = gridEntities[posId] local breaked, isIdle = entity:tryBreakGrid(condition, true) local aniUnit = self:getEliminattionAniInfo(posId, time) aniUnit.noAni = entity:isElmentTypeInvalid() aniUnit.isIdle = isIdle if entity:getSkillId() then aniUnit.isSkill = true end if breaked or entity:canBreakByThisCondition(condition) then breakedMap[posId] = true aniUnit.breakSfxName = entity:getBreakSfx() aniUnit.callback = function() local gridType = entity:getGridType() self.lastRoundBreakedGridType[gridType] = true self.totalBreakedGridType[gridType] = (self.totalBreakedGridType[gridType] or 0) + 1 entity:tryBreakGrid(condition) if entity:getIsIdle() then self:dealGridEdge(posId) end end table.insert(aniSequence, aniUnit) end if isIdle then if condition == GRID_BREAK_CONDITION.LINE then local outline = BattleConst.UP_DOWN_LEFT_RIGHT[posId] for _, id in ipairs(outline) do if self.battleData:getGridEntity(id) then if not BOARD_HELER:hasGridEdgeBetween(self, posId, id) then self:dealGridBreak(id, GRID_BREAK_CONDITION.AROUND, time, breakedMap, sequenceMap, aniSequence, gridMap, onlyCheck) end end end end if entity:getEffectType() then local succ, list = BATTLE_GRID_EFFECT_HANDLE.gridEffectOn(posId, gridEntities, BattleConst.GRID_EFFECT_TRIGGER_TYPE.ON_GRID_BREAK, self, onlyCheck) if list then aniUnit.aniPosList = table.clearOrCreate(aniUnit.aniPosList) aniUnit.overCallback = aniUnit.callback aniUnit.callback = nil for index, id in ipairs(list) do if id ~= posId then local timeIdx = time + BattleConst.GRID_BREAK_EFFECT_INTERVAL * (index - 1) -- 因为第一个是自己,所以-1 self:dealGridBreak(id, GRID_BREAK_CONDITION.SKILL, timeIdx, breakedMap, sequenceMap, aniSequence, gridMap, onlyCheck) table.insert(aniUnit.aniPosList, id) end end ---- 技能效果特效 aniUnit.effectSfxName = entity:getEffectSfx() aniUnit.effectSfxFlow = entity:getEffectSfxFlow() aniUnit.effectSfxDir = entity:getEffectParams()[1] end end aniUnit.bftcTime = entity:getBftcTime() if entity:getBreakFlyToCharacter() then aniUnit.breakFlyToCharacter = true aniUnit.noAni = false aniUnit.overCallback = aniUnit.callback aniUnit.callback = nil if entity:getBreakFlyToCharacterIcon() then aniUnit.callback = function() local cell = entity:getCell() if not cell then return end cell:setGridTypeIcon(entity:getBreakFlyToCharacterIcon()) self:dealGridEdge(posId) end end end end return isIdle end function BattleBaseController:dealGridEdge(posId) -- 能进来一定已经可以消除了 if not self.upDownLeftRightList then self.upDownLeftRightList = {BattleConst.BOARD_RANGE_TYPE.UP, BattleConst.BOARD_RANGE_TYPE.DOWN, BattleConst.BOARD_RANGE_TYPE.LEFT, BattleConst.BOARD_RANGE_TYPE.RIGHT} self.upDownLeftRightOppositeMap = { [BattleConst.BOARD_RANGE_TYPE.UP] = BattleConst.BOARD_RANGE_TYPE.DOWN, [BattleConst.BOARD_RANGE_TYPE.DOWN] = BattleConst.BOARD_RANGE_TYPE.UP, [BattleConst.BOARD_RANGE_TYPE.LEFT] = BattleConst.BOARD_RANGE_TYPE.RIGHT, [BattleConst.BOARD_RANGE_TYPE.RIGHT] = BattleConst.BOARD_RANGE_TYPE.LEFT } end for _, direction in ipairs(self.upDownLeftRightList) do -- 周围的 local aroundId = ModuleManager.BattleManager:getPosByDirection(posId, direction, self.battleData:getRowCount()) if aroundId then local breaked, breakSfx, breakCount, cell = self.battleData:breakGridEdge(aroundId, self.upDownLeftRightOppositeMap[direction]) if breaked and breakSfx and breakCount and cell then if self.battleUI then self.battleUI:getSfxGridEdgeBreak(breakSfx, breakCount, function(obj) local posX, posY = cell:getBaseObject():fastGetAnchoredPosition() obj:setLocalPosition(posX, posY, 0) obj:play() end) end end end -- 本身 local breaked, breakSfx, breakCount, cell = self.battleData:breakGridEdge(posId, direction) if breaked and breakSfx and breakCount and cell then if self.battleUI then self.battleUI:getSfxGridEdgeBreak(breakSfx, breakCount, function(obj) local posX, posY = cell:getBaseObject():fastGetAnchoredPosition() obj:setLocalPosition(posX, posY, 0) obj:play() end) end end end end function BattleBaseController:dealSkillElement(time, breakedMap, sequenceMap, aniSequence, boomGridIds, onlyCheck) local randomPosList local influenceElementTypeMap = {} for posId, info in pairs(self.battleData:getSkillInfluenceGrids()) do local entity = self.battleData:getGridEntity(posId) if not entity:getIsIdle() then if entity:isEmptyIdle() then if info.direction == BattleConst.BOARD_RANGE_TYPE.RANDOM then if not randomPosList then randomPosList = {} end table.insert(randomPosList, posId) end influenceElementTypeMap[entity:getElementType()] = (influenceElementTypeMap[entity:getElementType()] or 0) + 1 end self:dealGridBreak(posId, GRID_BREAK_CONDITION.SKILL, time, breakedMap, sequenceMap, aniSequence, boomGridIds, onlyCheck) end end return randomPosList, influenceElementTypeMap end function BattleBaseController:getEliminattionAniInfo(posId, timeIdx) return { posId = posId, noAni = nil, aniPosList = nil, breakSfxName = nil, timeIdx = timeIdx, conditions = nil, isSkill = false, isIdle = false, callback = nil, overCallback = nil, bftcTime = 0, effectSfxName = nil, effectSfxFlow = nil, effectSfxDir = nil, } end function BattleBaseController:setGridBreakCondition(gridMap, posId, condition) if not gridMap[posId] then gridMap[posId] = {} gridMap[posId][condition] = true end gridMap[posId][condition] = true end function BattleBaseController:tryShowSelectSkillComp(needDelay, onlyCommonSkill) self.canChoseSkillCount = 1 local skillList = self:getRandomSkillList(nil, onlyCommonSkill) if needDelay then self.showSelectSkillSid = ModuleManager.BattleManager:performWithDelayGlobal(function() self.battleUI:showSelectSkillComp(skillList, onlyCommonSkill) self.showSelectSkillSid = nil end, 0.3) else self.battleUI:showSelectSkillComp(skillList, onlyCommonSkill) end BIReport:postShowFightSkillSelect(self.battleType, self.battleData, skillList, self.chapterId, self.totalDurationTime, self:getWaveIndex()) end function BattleBaseController:fillBoard(isRoundBeginCheck) local reverse = self.curActionSide == SIDE_DEF self.fillBoardPathMap = table.clearOrCreate(self.fillBoardPathMap) self.fillColumnCount = table.clearOrCreate(self.fillColumnCount) self.fillGridMap = table.clearOrCreate(self.fillGridMap) if reverse then for c = 1, BattleConst.COLUMN_COUNT do for r = 1, self:getRowCount() do local posId = ModuleManager.BattleManager:getPosId(r, c) local entity = self.battleData:getGridEntity(posId) if entity and entity:getIsIdle() then self:fillThisPos(posId, self.fillColumnCount, self.fillGridMap, reverse) end end end else for c = 1, BattleConst.COLUMN_COUNT do for r = self:getRowCount(), 1, -1 do local posId = ModuleManager.BattleManager:getPosId(r, c) local entity = self.battleData:getGridEntity(posId) if entity and entity:getIsIdle() then self:fillThisPos(posId, self.fillColumnCount, self.fillGridMap, reverse) end end end end while true do local find = false for c = 1, BattleConst.COLUMN_COUNT do local list = self.fillGridMap[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 posId, entity in pairs(self.battleData:getGridEnties()) do if #entity:getPath() > 0 then self.fillBoardPathMap[posId] = entity:getPath() entity:clearPath() end end self.battleUI:fallGrid(self.fillBoardPathMap, isRoundBeginCheck, function() self:onFillBoardOver(isRoundBeginCheck) self.isRoundBeginCheck = nil self.isWaitingFill = false end) end function BattleBaseController:onFillBoardOver(isRoundBeginCheck) self.battleUI:enableUITouch() if not isRoundBeginCheck then -- 检查一些表现 if self.showMysteryBoxIndexs[1] then -- 检查宝箱 local index = table.remove(self.showMysteryBoxIndexs, 1) local boardList, _, mysteryBoxIndexMap = self:getInitBoard() local rewards = mysteryBoxIndexMap[index] if rewards then ModuleManager.BattleManager:showBoxOpenUI(rewards, function() self:onFillBoardOver() end) else self:onFillBoardOver() end return end if self.battleData:useCommonSelectSkillCount() then -- 检查神灯 self:tryShowSelectSkillComp(false, true) return end end if isRoundBeginCheck then EventManager:dispatchEvent(EventManager.CUSTOM_EVENT.BOARD_FILL_OVER) self:popBoardCacheSkill(function() self:generateSkill(function() if self.onFillBoardOverCallback then local callback = self.onFillBoardOverCallback self.onFillBoardOverCallback = nil callback() else self:enterElimination(true) end end) end) else self:generateSkill(function() self.battleUI:refreshSkill(nil, nil, self:getCurActionSide()) if self.onFillBoardOverCallback then local callback = self.onFillBoardOverCallback self.onFillBoardOverCallback = nil callback() end end) end end function BattleBaseController:generateInstructions(skillEntity, elementType, lineCount, influenceElementTypeMap, elementTypeMap) self.instructions = BATTLE_INSTRUCTIONS_HELPER.generateInstructions(skillEntity, elementType, lineCount, influenceElementTypeMap, elementTypeMap, self) end function BattleBaseController:exeInstructions(callback, side) side = side or self:getCurActionSide() if not self.instructions or #self.instructions <= 0 then callback() return end local instruction = table.remove(self.instructions) local func = BattleBaseController._doInstruction[instruction.name] if func then func(self, side, instruction, function() self.battleData:resetTimeSpeed() self:exeInstructions(callback, side) end) else self:exeInstructions(callback, side) end end function BattleBaseController:getIsLastInstruction() if not self.instructions or not self.instructions[1] then return true end return false end function BattleBaseController:generateBoard(isFirst, snapshot) local boardList, _, mysteryBoxIndexMap = self:getInitBoard() if self.curBoardIndex and self.curBoardIndex >= #boardList then if isFirst then self.needWaitingBoardOver = false end return end if not self.battleUI then if isFirst then self.needWaitingBoardOver = false end return end self.curBoardIndex = (self.curBoardIndex or 0) + 1 if snapshot and snapshot.curBoardIndex then self.curBoardIndex = snapshot.curBoardIndex end if not boardList[self.curBoardIndex] then -- 容错 if isFirst then self.needWaitingBoardOver = false end return end local board = boardList[self.curBoardIndex].board local mysteryBoard = boardList[self.curBoardIndex].mysteryBoard if mysteryBoard and mysteryBoxIndexMap and mysteryBoxIndexMap[self.curBoardIndex] then board = mysteryBoard end local gridEdge = boardList[self.curBoardIndex].gridEdge self.battleUI:switchBoard(function() self.battleData:refreshBoard(board, gridEdge, self:getBlockIcon(), snapshot) self.battleUI:initGridCell(function() if isFirst then self.needWaitingBoardOver = false end end) end, function() end, isFirst) end function BattleBaseController:onGotMysteryBoxIndexs() self.gotMysteryBoxIndexs[self.curBoardIndex] = true table.insert(self.showMysteryBoxIndexs, self.curBoardIndex) end function BattleBaseController: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 BattleBaseController:popBoardCacheSkill(callback) local skillList, skillCount = self.battleData:getCacheBoardSkill() self.battleData:clearCacheBoardSkill() if self.battleUI and skillCount > 0 then self.popSkillPosIdList = table.clearOrCreate(self.popSkillPosIdList) for posId, entity in pairs(self.battleData:getGridEnties()) do if entity:isEmptyIdle() and not entity:getIsIdle() then table.insert(self.popSkillPosIdList, posId) end end self.popSkillPosIdList = table.shuffle(self.popSkillPosIdList) self.popNewSkillId = table.clearOrCreate(self.popNewSkillId) for index, info in ipairs(skillList) do if self.popSkillPosIdList[1] then self.popNewSkillId[index] = info self.popNewSkillId[index].posId = table.remove(self.popSkillPosIdList) self:setGridSkillId(self.popNewSkillId[index].posId, info.skillId, true) else break end end self.battleUI:cacheSkillAni(self.popNewSkillId, true, function() for index, info in ipairs(self.popNewSkillId) do self.battleData:setGridDirty(info.posId) end if callback then callback() end end) else if callback then callback() end end end function BattleBaseController:generateSkill(callback) self.generateSkillMap = table.clearOrCreate(self.generateSkillMap) self.generateExcludeMap = table.clearOrCreate(self.generateExcludeMap) for _, skillEntity in pairs(self:getSkillEntities()) do if skillEntity:getEnergyEnough() then local list = self:getSkillElementList(skillEntity:getPosition(), 1, true, self.generateExcludeMap) if list[1] then self.generateSkillMap[skillEntity:getPosition()] = { skillId = skillEntity:getSkillId(), posId = list[1] } self.generateExcludeMap[list[1]] = true end end end if not self.battleUI then if callback then callback() end return end self.battleUI:generateSkillAni(self.generateSkillMap, function() for elementType, info in pairs(self.generateSkillMap) do self:setGridSkillId(info.posId, info.skillId) end if callback then callback() end end, self.curActionSide) end function BattleBaseController:setGridSkillId(posId, skillId, noDirty) local entity = self.battleData:getGridEntity(posId) if entity then entity:setSkilId(skillId, noDirty, self.curActionSide) local skillEntity = self:getSkillEntityBySkillId(skillId) if skillEntity and entity:getElementType() ~= skillEntity:getPosition() then entity:setElementType(skillEntity:getPosition(), noDirty) end end end function BattleBaseController:generateGridType(skillTypeParameter, monsterPos) if not skillTypeParameter then return end self.generateGridTypeList = table.clearOrCreate(self.generateGridTypeList) local count = 0 for posId, entity in pairs(self.battleData:getGridEnties()) do if entity:isEmptyIdle() then table.insert(self.generateGridTypeList, entity) count = count + 1 end end self.generateGridTypeList = table.shuffle(self.generateGridTypeList) if count > 0 then self.generateGridTypeMap = table.clearOrCreate(self.generateGridTypeMap) local minCount = math.min(skillTypeParameter[2], count) for i = minCount, 1, -1 do local entity = table.remove(self.generateGridTypeList, math.random(1, i)) self.generateGridTypeMap[entity:getPosId()] = { gridType = skillTypeParameter[1], elementType = entity:getElementType() } end self.battleUI:showMonsterSkillAni(self.generateGridTypeMap, monsterPos, function() for posId, info in pairs(self.generateGridTypeMap) do self.battleData:setGridInfo(posId, info) end end) end end function BattleBaseController:lockElement(lcokElementType, isUnlock) if not self.lockElementElementTypeMap then self.lockElementElementTypeMap = table.clearOrCreate(self.lockElementElementTypeMap) else for k, v in pairs(self.lockElementElementTypeMap) do self.lockElementElementTypeMap[k] = table.clearOrCreate(self.lockElementElementTypeMap[k]) end end if not self.lockElementMap then self.lockElementMap = table.clearOrCreate(self.lockElementMap) else for k, v in pairs(self.lockElementMap) do self.lockElementMap[k] = table.clearOrCreate(self.lockElementMap[k]) end end self.lockElementList = table.clearOrCreate(self.lockElementList) local locked = false for posId, entity in pairs(self.battleData:getGridEnties()) do local elementType = entity:getElementType() if not isUnlock then if entity:isEmptyIdle() then local elementTypeMapUnit = self.lockElementElementTypeMap[elementType] if not elementTypeMapUnit or not elementTypeMapUnit[1] then self.lockElementElementTypeMap[elementType] = table.clearOrCreate(self.lockElementElementTypeMap[elementType]) elementTypeMapUnit = self.lockElementElementTypeMap[elementType] if not isUnlock then table.insert(self.lockElementList, elementType) end end table.insert(elementTypeMapUnit, posId) end if entity:isLock() then locked = true end else if entity:isLock() then if not self.lockElementMap[elementType] then self.lockElementMap[elementType] = table.clearOrCreate(self.lockElementMap[elementType]) end table.insert(self.lockElementMap[elementType], posId) end end end if isUnlock then self.battleData:clearAllCacheLockElement(lcokElementType, nil) for elementType, list in pairs(self.lockElementMap) do for _, posId in ipairs(list) do self.battleData:setGridType(posId, BattleConst.GRID_TYPE.EMPTY) end end else if locked then -- 锁定过就不新锁了 return end local elementType = lcokElementType if elementType == BattleConst.ELEMENT_TYPE.NONE then if not self.lockElementList[1] then return end elementType = self.lockElementList[math.random(1, #self.lockElementList)] end self.battleData:cacheLockElement(elementType, true) local list = self.lockElementElementTypeMap[elementType] if list then for _, posId in ipairs(list) do self.battleData:setGridType(posId, BattleConst.GRID_TYPE.LOCK) end end end end function BattleBaseController:getSkillElementListRow() self.skillElementListRow = table.clearOrCreate(self.skillElementListRow) local min, max = self:getCurActionBoardRowRange() for row = min, max do table.insert(self.skillElementListRow, row) end return self.skillElementListRow end function BattleBaseController:getSkillElementList(elementType, count, useAlternate, excludeMap) self.getSkillElementListResult = table.clearOrCreate(self.getSkillElementListResult) local gridEntities = self.battleData:getGridEnties() if not gridEntities then return self.getSkillElementListResult end self.getSkillElementListSameElementList = table.clearOrCreate(self.getSkillElementListSameElementList) self.getSkillElementListAlternateList = table.clearOrCreate(self.getSkillElementListAlternateList) local addCount = 0 for _, row in ipairs(self:getSkillElementListRow()) 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(self.getSkillElementListSameElementList, posId) else table.insert(self.getSkillElementListAlternateList, posId) end end end local remainCount = count - addCount if remainCount <= 0 then return self.getSkillElementListResult end for i = 1, remainCount do if not self.getSkillElementListSameElementList[i] then break end table.insert(self.getSkillElementListResult, table.remove(self.getSkillElementListSameElementList, math.random(1, #self.getSkillElementListSameElementList))) addCount = addCount + 1 if addCount >= count then return self.getSkillElementListResult end end if addCount < count and useAlternate then for i = 1, count - addCount do if not self.getSkillElementListAlternateList[1] then break end table.insert(self.getSkillElementListResult, table.remove(self.getSkillElementListAlternateList, math.random(1, #self.getSkillElementListAlternateList))) addCount = addCount + 1 if addCount >= count then return self.getSkillElementListResult end end end if addCount >= count then return self.getSkillElementListResult end end return self.getSkillElementListResult end ---- 从一个点直接遍历所有相关的路径 function BattleBaseController:fillThisPos(posId, columnCount, gridMap, reverse) local entity = self.battleData:getGridEntity(posId) if not entity or not entity:getIsIdle() then return end local list if reverse then list = BattleConst.DOWN_LINE_FILL_LIST[posId] else list = BattleConst.UP_LINE_FILL_LIST[posId] end if not list[1] then -- 第一排 if reverse then local gridEdgeEntity = self.battleData:getGridEdgeEntity(posId, BattleConst.BOARD_RANGE_TYPE.DOWN) if gridEdgeEntity and not gridEdgeEntity:getIsIdle() then return end else local gridEdgeEntity = self.battleData:getGridEdgeEntity(posId, BattleConst.BOARD_RANGE_TYPE.UP) if gridEdgeEntity and not gridEdgeEntity:getIsIdle() then return end end 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 if reverse then newStartPosId = ModuleManager.BattleManager:getLastLineLastRowPosId(i, c, self:getRowCount()) else newStartPosId = ModuleManager.BattleManager:getFirstLineLastRowPosId(i, c) end local curPos = self:getPosInfo(newStartPosId) fallEntity:addPath({x = curPos.x, y = curPos.y}) end local curPos = self: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 self:judgeGridEdgeCanFall(posId, fallPosId, reverse) then if not fallEntity:isCantFallType() then if fallEntity:getIsIdle() then self:fillThisPos(fallPosId, columnCount, gridMap, reverse) end fallEntity = self.battleData:getGridEntity(fallPosId) if not fallEntity:getIsIdle() then if not fallEntity:getPath()[1] then local curPos = self:getPosInfo(fallPosId) fallEntity:addPath({x = curPos.x, y = curPos.y}) end local curPos = self:getPosInfo(posId) fallEntity:addPath({x = curPos.x, y = curPos.y}) self.battleData:exchangeGridEntities(posId, fallPosId) self:fillThisPos(fallPosId, columnCount, gridMap, reverse) return end end end end end end function BattleBaseController:judgeGridEdgeCanFall(posId, fallPosId, reverse) return BattleBoardTouchHelper:judgeGridEdgeCanLink(fallPosId, posId) end function BattleBaseController: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() self.getRandomGridInfoIndexs = table.clearOrCreate(self.getRandomGridInfoIndexs) self.getRandomGridInfoTypeList = table.clearOrCreate(self.getRandomGridInfoTypeList) for typeName, typeNum in pairs(BattleConst.ELEMENT_TYPE) do if not self:getSealElementType()[typeNum] and self:getSkillEntityByElement(typeNum) then local weight = ((map[typeNum] or 0) + 1) * BattleConst.ELEMENT_WIGHT if self.elementWeightMap and self.elementWeightMap[typeNum] then weight = weight + self.elementWeightMap[typeNum] end if weight > BattleConst.MAX_ELEMENT_WIGHT then weight = BattleConst.MAX_ELEMENT_WIGHT end table.insert(self.getRandomGridInfoIndexs, weight) table.insert(self.getRandomGridInfoTypeList, typeNum) end end local index = GFunc.getRandomIndex(self.getRandomGridInfoIndexs) elementType = self.getRandomGridInfoTypeList[index] end return {gridType = gridType, elementType = elementType} end function BattleBaseController: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() self.skillInfluenceGridsSequenceEntities = table.clearOrCreate(self.skillInfluenceGridsSequenceEntities) for _, info in ipairs(sequence) do local entity = self.battleData:getGridEntity(info.posId) table.insert(self.skillInfluenceGridsSequenceEntities, 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:getSkillEntityBySkillId(skillId) if skillEntity then BATTLE_BOARD_SKILL_HANDLE.activeBoardSkill(info.posId, skillEntity, self.battleData:getGridEnties(), self.skillInfluenceGridsSequenceEntities, self) end end end end function BattleBaseController:getRandomSkillList(getCount, onlyCommonSkill, excludeMap) local fixedList = self:getFixedRogueSkill() if fixedList[1] then return table.remove(fixedList, 1) end getCount = getCount or BattleConst.SKILL_SELECT_COUNT self.randomSkillList = table.clearOrCreate(self.randomSkillList) self.randomSkillMap = table.clearOrCreate(self.randomSkillMap) self.randomSkillNewSkillPool = table.clearOrCreate(self.randomSkillNewSkillPool) self.randomSkillSkillWeight = table.clearOrCreate(self.randomSkillSkillWeight) local cfg = ConfigManager:getConfig("skill_rogue") local skillPool = self:getSkillPool() local count = 0 if not onlyCommonSkill then for elementType, list in pairs(skillPool) do -- 先遍历一下未解锁的技能 if not self:isUnlockedSkillElementType(elementType) then local skillEntity = self:getSkillEntityByElement(elementType) if skillEntity then local skillId = skillEntity:getUnlockId() if skillId and not self.randomSkillMap[skillId] then local skillCfg = cfg[skillId] table.insert(self.randomSkillNewSkillPool, skillId) table.insert(self.randomSkillSkillWeight, skillCfg.weight) count = count + 1 self.randomSkillMap[skillId] = true end end end end if count >= 3 then -- 如果未解锁的技能大于等于3,则直接返回三个解锁技能 for i = 1, 3 do local index = GFunc.getRandomIndex(self.randomSkillSkillWeight) local skillId = table.remove(self.randomSkillNewSkillPool, index) table.remove(self.randomSkillSkillWeight, index) count = count - 1 table.insert(self.randomSkillList, skillId) end return table.shuffle(self.randomSkillList) end if excludeMap then for skillId, _ in pairs(excludeMap) do self.randomSkillMap[skillId] = true end end for elementType, list in pairs(skillPool) do if self:isUnlockedSkillElementType(elementType) then for _, skillId in ipairs(list) do local skillCfg = cfg[skillId] if skillCfg and (not skillCfg.limit_times or self:getSkillCount(skillId) < skillCfg.limit_times) then if not self.randomSkillMap[skillId] and (not skillCfg.unlock or self:getSkillCount(skillCfg.unlock) > 0) then table.insert(self.randomSkillNewSkillPool, skillId) table.insert(self.randomSkillSkillWeight, skillCfg.weight) count = count + 1 self.randomSkillMap[skillId] = true end end end end end if count > 0 then local index = GFunc.getRandomIndex(self.randomSkillSkillWeight) local skillId = table.remove(self.randomSkillNewSkillPool, index) table.remove(self.randomSkillSkillWeight, index) count = count - 1 table.insert(self.randomSkillList, skillId) getCount = getCount - 1 end 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:getSkillCount(skillId) < info.limit_times then if not self.randomSkillMap[skillId] then table.insert(self.randomSkillNewSkillPool, skillId) table.insert(self.randomSkillSkillWeight, info.weight) count = count + 1 end end end end end for i = 1, getCount do local index = GFunc.getRandomIndex(self.randomSkillSkillWeight) local skillId = table.remove(self.randomSkillNewSkillPool, index) table.remove(self.randomSkillSkillWeight, index) count = count - 1 table.insert(self.randomSkillList, skillId) if count <= 0 then break end end local result = table.shuffle(self.randomSkillList) return result end function BattleBaseController:dealSelectSkill(skillId, value, side, isSnapshot) side = side or self:getCurActionSide() self.battleData:addSkillCount(skillId, value, side) BATTLE_ROGUE_SKILL_HANDLE.takeEffect(skillId, self.battleData, self, value, side, isSnapshot) local skillEntities = self:getSkillEntities(side) for _, entity in pairs(skillEntities) do entity:gotUpSKill(skillId) end end function BattleBaseController:onSelectSkill(skillId, value, pos, side) if not self.canChoseSkillCount or self.canChoseSkillCount <= 0 then return end self.canChoseSkillCount = self.canChoseSkillCount - 1 side = side or self:getCurActionSide() self:dealSelectSkill(skillId, value, side) BIReport:postFightSkillSelect(self.battleType, self.battleData, {skillId}, self.chapterId, self.totalDurationTime, self:getWaveIndex()) local elementType = ModuleManager.HeroManager:getSkillRoguePosition(skillId) if elementType then if self.battleUI then self.battleUI:gotOneSkillAni(skillId, elementType, function() self:selectSKillNextToStep() self.battleUI:refreshBoard() self.battleUI:refreshSkill(nil, nil, self:getCurActionSide()) end, pos) return end end self:selectSKillNextToStep() self.battleUI:showCommonSkillTips(skillId) end function BattleBaseController:selectSKillNextToStep() if self.roundStep == BattleConst.BATTLE_ROUND_STEP.ON_REFRESH_BOARD then self:onFillBoardOver() else self:enterElimination() end end function BattleBaseController:changeElementType(count, elementType, side) self.changeElementTypeMap = table.clearOrCreate(self.changeElementTypeMap) self.changeElementTypeList = table.clearOrCreate(self.changeElementTypeList) local listCount = 0 for _, entity in pairs(self.battleData:getGridEnties()) do if entity:canChangeInfo() and entity:getElementType() ~= elementType then if side then if self:getPosIdInActionBoardRowRange(side, entity:getPosId()) then table.insert(self.changeElementTypeList, entity) listCount = listCount + 1 end else table.insert(self.changeElementTypeList, entity) listCount = listCount + 1 end end end count = math.min(count, listCount) for i = 1, count do if listCount <= 0 then break end local index = math.random(1, listCount) self.changeElementTypeList[index], self.changeElementTypeList[listCount] = self.changeElementTypeList[listCount], self.changeElementTypeList[index] local entity = table.remove(self.changeElementTypeList) listCount = listCount - 1 self.changeElementTypeMap[entity] = elementType end self:changeElementTypeByMap(self.changeElementTypeMap) end function BattleBaseController:changeElementTypeByMap(changeMap) local index = 1 for entity, elementType in pairs(changeMap) do self.battleData:setGridInfo(entity:getPosId(), {gridType = entity:getGridType(), elementType = elementType}) self.battleUI:playChangeElementSfx(entity:getPosId(), index) index = index + 1 end end function BattleBaseController:killGrids(posIdList) if not posIdList[1] then return end for _, posId in ipairs(posIdList) do local entity = self.battleData:getGridEntity(posId) entity:setIsIdle(true) end self.battleUI:removeGridOutOfScreen(posIdList) end function BattleBaseController:killRowOrColumn(infoList) self.killRowOrColumnMap = table.clearOrCreate(self.killRowOrColumnMap) for _, info in ipairs(infoList) do if info.posList then for i, posId in ipairs(info.posList) do if not self.killRowOrColumnMap[posId] then self.killRowOrColumnMap[posId] = true local entity = self.battleData:getGridEntity(posId) entity:setIsIdle(true) end end self.battleUI:removeGridOutOfScreen(info.posList) end end end function BattleBaseController:addHeroAttr(attrName, value, side) if not self.battleData or not self.battleData.atkTeam then return end local attr = BUFF_NAME_TO_ATTR[attrName] if attr then self.battleData:getTeamBySide(side):addAttr(attr[1], value, attr[2]) else local func = BattleBuffHandle.addAttribute[attrName] if func then local unitComp for matchType, comp in pairs(self:getCurActionTeam(side):getUnitComp()) do unitComp = comp break end if unitComp then func(unitComp, value) end end end end ---- 快照一次棋盘 function BattleBaseController:snapshotBoard() local snapshot = {} for _, entity in pairs(self.battleData:getGridEnties()) do snapshot[entity:getPosId()] = entity:getSnapshoptInfo() end return snapshot end function BattleBaseController:snapshotGridEdge() local snapshot = {} for posId, info in pairs(self.battleData:getGridEdgeEntities()) do for direction, entity in pairs(info) do if not entity:getIsIdle() then table.insert(snapshot, {pos = posId, type = entity:getType(), direction = direction}) end end end return snapshot end function BattleBaseController:showAttention() if not self.attentionList then return end if self.attentionSid then ModuleManager.BattleManager:unscheduleGlobal(self.attentionSid) self.attentionSid = nil end self.attentionSid = ModuleManager.BattleManager:performWithDelayGlobal(function() for _, posId in ipairs(self.attentionList) do local entity = self.battleData:getGridEntity(posId) if entity and entity:getCell() then entity:getCell():showAni() end end end, 2) end function BattleBaseController:shuffleBoard(callback) local changeInfo = self:getShuffleBoardInfo() if changeInfo then self.battleData:setGridEntitiesPosId(changeInfo) self.battleUI:shuffleBoard(changeInfo, callback) else self.resetList = table.clearOrCreate(self.resetList) for posId, entity in pairs(self.battleData:getGridEnties()) do if self:getPosIdInCurActionBoardRowRange(posId) and entity:isCanFallStatus() and not entity:getCantUpset() then table.insert(self.resetList, entity) end end local resetInfo = self:resetGrids(self.resetList) if not resetInfo then if EDITOR_MODE then Logger.logHighlight("----- 处于无法消除状态 -----") end if callback then callback() end else if self.resetGridSid then ModuleManager.BattleManager:unscheduleGlobal(self.resetGridSid) self.resetGridSid = nil end self.resetGridSid = ModuleManager.BattleManager:performWithDelayGlobal(function() local count = 1 for posId, info in pairs(resetInfo) do self.battleData:setInfoBySnapshop(posId, info) self.battleUI:playChangeElementSfx(posId, count) count = count + 1 end self.resetGridSid = nil if callback then callback() end end, 0.5) end end end function BattleBaseController:getShuffleBoardInfo() self.shuffleBoardPosList = table.clearOrCreate(self.shuffleBoardPosList) self.shuffleBoardAnySkillList = table.clearOrCreate(self.shuffleBoardAnySkillList) self.shuffleBoardPosMap = table.clearOrCreate(self.shuffleBoardPosMap) self.shuffleBoardCountMap = table.clearOrCreate(self.shuffleBoardCountMap) self.shuffleBoardCantLinkMap = table.clearOrCreate(self.shuffleBoardCantLinkMap) if not self.shuffleBoardList then self.shuffleBoardList = table.clearOrCreate(self.shuffleBoardList) else for elementType, _ in pairs(self.shuffleBoardList) do self.shuffleBoardList[elementType] = table.clearOrCreate(self.shuffleBoardList[elementType]) end end local anySkillCount = 0 for posId, entity in pairs(self.battleData:getGridEnties()) do if self:getPosIdInCurActionBoardRowRange(posId) and entity:isCanFallStatus() and not entity:getCantUpset() then if entity:getSkillId() then local skillEntity = self:getSkillEntityBySkillId(entity:getSkillId()) local elementType = skillEntity:getPosition() if skillEntity:getIgnoreElementType() then table.insert(self.shuffleBoardAnySkillList, entity) anySkillCount = anySkillCount + 1 else if not self.shuffleBoardList[elementType] then self.shuffleBoardList[elementType] = table.clearOrCreate(self.shuffleBoardList[elementType]) end table.insert(self.shuffleBoardList[elementType], entity) self.shuffleBoardCountMap[elementType] = (self.shuffleBoardCountMap[elementType] or 0) + 1 end else local elementType = entity:getElementType() if not self.shuffleBoardList[elementType] then self.shuffleBoardList[elementType] = table.clearOrCreate(self.shuffleBoardList[elementType]) end table.insert(self.shuffleBoardList[elementType], entity) self.shuffleBoardCountMap[elementType] = (self.shuffleBoardCountMap[elementType] or 0) + 1 if not entity:canLink() then self.shuffleBoardCantLinkMap[elementType] = (self.shuffleBoardCantLinkMap[elementType] or 0) + 1 end end table.insert(self.shuffleBoardPosList, posId) self.shuffleBoardPosMap[posId] = true end end for elementType, list in pairs(self.shuffleBoardList) do table.sort(self.shuffleBoardList[elementType], function(a, b) if a:getSkillId() and not b:getSkillId() then return false elseif not a:getSkillId() and b:getSkillId() then return true else return a:getPosId() < b:getPosId() end end) end local needCount = self:getMinEliminationCount() local find = false for elementType, list in pairs(self.shuffleBoardList) do local count = self.shuffleBoardCountMap[elementType] or 0 local cantLinkCount = self.shuffleBoardCantLinkMap[elementType] or 0 local skillCount = 0 if anySkillCount > 0 then skillCount = 1 end if count + skillCount - cantLinkCount >= needCount then local haveSkill = false local listCount = 0 self.shuffleBoardTempList = table.clearOrCreate(self.shuffleBoardTempList) find = false local add = false for _, entity in ipairs(list) do add = false if haveSkill then if not entity:getSkillId() then add = entity:canLink() end else if entity:getSkillId() then haveSkill = true end add = entity:canLink() end if add then table.insert(self.shuffleBoardTempList, entity) listCount = listCount + 1 if listCount >= needCount then -- 可连接的 普通的元素+元素技能 find = true break end end end if listCount >= needCount then -- 可连接的 普通的元素+元素技能 find = true break elseif not haveSkill and skillCount > 0 then -- 可连接的 普通元素 + 任意元素技能 table.insert(self.shuffleBoardTempList, self.shuffleBoardAnySkillList[1]) listCount = listCount + 1 if listCount >= needCount then find = true break end end end end if find then return self:shufflePos(self.shuffleBoardTempList, self.shuffleBoardPosMap, needCount, self.shuffleBoardPosList) end end function BattleBaseController:shufflePos(tempList, posMap, needCount, posList) local gotPos, useMap, list = self:findCanLinkPosList(posMap, needCount) if gotPos and list[1] then self.shufflePosInfo = table.clearOrCreate(self.shufflePosInfo) self.shufflerPosUsedPos = table.clearOrCreate(self.shufflerPosUsedPos) self.shufflerSetedPos = table.clearOrCreate(self.shufflerSetedPos) for index, entity in ipairs(tempList) do self.shufflePosInfo[entity:getPosId()] = list[index] self.shufflerPosUsedPos[list[index]] = true self.shufflerSetedPos[entity:getPosId()] = true end self.shufflePosList1 = table.clearOrCreate(self.shufflePosList1) self.shufflePosList2 = table.clearOrCreate(self.shufflePosList2) for index = #posList, 1, -1 do local posId = posList[index] if not self.shufflerPosUsedPos[posId] then table.insert(self.shufflePosList2, posId) end if not self.shufflerSetedPos[posId] then table.insert(self.shufflePosList1, posId) end end self.shufflePosList2 = table.shuffle(self.shufflePosList2) for index, posId in ipairs(self.shufflePosList1) do if not self.shufflePosList2[index] then break end self.shufflePosInfo[posId] = self.shufflePosList2[index] end return self.shufflePosInfo end end function BattleBaseController:findAttention() local find = false local min, max = self:getCurActionBoardRowRange() for r = min, max do for c = 1, GConst.BattleConst.COLUMN_COUNT do local posId = ModuleManager.BattleManager:getPosId(r, c) local gridEntity = self.battleData:getGridEntity(posId) local mainElementType = gridEntity:getElementType() if gridEntity:canChangeInfo() then self.findAttentionPathList = table.clearOrCreate(self.findAttentionPathList) self.findAttentionPosIdMap = table.clearOrCreate(self.findAttentionPosIdMap) self:findLinkLine(posId, self.findAttentionPosIdMap, false, mainElementType, self.findAttentionPathList) if table.nums(self.findAttentionPathList) >= self:getMinEliminationCount() then find = true break end end end if find then break end end return find, self.findAttentionPathList end function BattleBaseController:_dealResetGridsDataFunc(posList) self.dealResetFunc1PosMap = table.clearOrCreate(self.dealResetFunc1PosMap) self.dealResetFunc1LockElementMap = table.clearOrCreate(self.dealResetFunc1LockElementMap) self.dealResetFunc1KeepSnapList = table.clearOrCreate(self.dealResetFunc1KeepSnapList) self.dealResetFunc1KeepSnapSkillList = table.clearOrCreate(self.dealResetFunc1KeepSnapSkillList) self.dealResetFunc1EmptySnapList = table.clearOrCreate(self.dealResetFunc1EmptySnapList) local emptyCount = 0 for _, entity in ipairs(posList) do local posId = entity:getPosId() self.dealResetFunc1PosMap[posId] = entity if entity:isEmptyIdle() then emptyCount = emptyCount + 1 table.insert(self.dealResetFunc1EmptySnapList, entity:getSnapshoptInfo()) elseif entity:isLock() and not entity:getSkillId() then self.dealResetFunc1LockElementMap[entity:getElementType()] = true emptyCount = emptyCount + 1 local snapInfo = entity:getSnapshoptInfo() snapInfo.gridType = BattleConst.GRID_TYPE.EMPTY table.insert(self.dealResetFunc1EmptySnapList, snapInfo) else if entity:getSkillId() then table.insert(self.dealResetFunc1KeepSnapSkillList, entity:getSnapshoptInfo()) else table.insert(self.dealResetFunc1KeepSnapList, entity:getSnapshoptInfo()) end end end return self.dealResetFunc1PosMap, self.dealResetFunc1LockElementMap, emptyCount, self.dealResetFunc1KeepSnapList, self.dealResetFunc1KeepSnapSkillList, self.dealResetFunc1EmptySnapList end function BattleBaseController:_dealResetGridsDataFunc2(useMap, emptySnapList, mainElement, backupSkill, keepSnapList, posMap, canRandomElmentList, elementCount, lockElementMap) self.dealResetFunc2ResetPosInfo = table.clearOrCreate(self.dealResetFunc2ResetPosInfo) for posId, _ in pairs(useMap) do local snapInfo if emptySnapList[1] then snapInfo = table.remove(emptySnapList) snapInfo.elementType = mainElement snapInfo.posId = posId snapInfo.gridType = BattleConst.GRID_TYPE.EMPTY else snapInfo = backupSkill end self.dealResetFunc2ResetPosInfo[posId] = snapInfo end for _, snap in ipairs(emptySnapList) do table.insert(keepSnapList, snap) end keepSnapList = table.shuffle(keepSnapList) for posId, entity in pairs(posMap) do if not useMap[posId] then local snapInfo if keepSnapList[1] then snapInfo = table.remove(keepSnapList) snapInfo.posId = posId if not snapInfo.skillId or snapInfo.skillId <= 0 then if snapInfo.gridType == BattleConst.GRID_TYPE.EMPTY then snapInfo.elementType = canRandomElmentList[math.random(1, elementCount)] if lockElementMap[snapInfo.elementType] then snapInfo.gridType = BattleConst.GRID_TYPE.LOCK end end end end if snapInfo then self.dealResetFunc2ResetPosInfo[posId] = snapInfo end end end return self.dealResetFunc2ResetPosInfo end function BattleBaseController:resetGrids(posList) local needCount = self:getMinEliminationCount() if not posList[needCount] then return end local posMap, lockElementMap, emptyCount, keepSnapList, keepSnapSkillList, emptySnapList = self:_dealResetGridsDataFunc(posList) local canUseSkillCount = 0 if keepSnapSkillList[1] then -- 技能可以直接链接, 不判断元素技能了 canUseSkillCount = 1 end if emptyCount + canUseSkillCount < needCount then -- 格子不够 return end local backupSkill if emptyCount < needCount then backupSkill = table.remove(keepSnapSkillList) end for _, snap in ipairs(keepSnapSkillList) do table.insert(keepSnapList, snap) end local gotPos, useMap = self:findCanLinkPosList(posMap, needCount) if not gotPos then return end self.canRandomElmentList = table.clearOrCreate(self.canRandomElmentList) local elementCount = 0 for typeName, typeNum in pairs(BattleConst.ELEMENT_TYPE) do if not lockElementMap[typeNum] and not self:getSealElementType()[typeNum] and self:getSkillEntityByElement(typeNum) then table.insert(self.canRandomElmentList, typeNum) elementCount = elementCount + 1 end end if elementCount <= 0 then return end local mainElement = self.canRandomElmentList[math.random(1, elementCount)] for typeNum, _ in pairs(lockElementMap) do table.insert(self.canRandomElmentList, typeNum) elementCount = elementCount + 1 end local resetPosInfo = self:_dealResetGridsDataFunc2(useMap, emptySnapList, mainElement, backupSkill, keepSnapList, posMap, self.canRandomElmentList, elementCount, lockElementMap) return resetPosInfo end function BattleBaseController:findCanLinkPosList(posMap, needCount) self.findCanLinkList = table.clearOrCreate(self.findCanLinkList) self.findCanUseMap = table.clearOrCreate(self.findCanUseMap) local gotPos = false for posId, _ in pairs(posMap) do table.clear(self.findCanLinkList) table.clear(self.findCanUseMap) local count = 0 local findPodId = posId gotPos = false while true do local aounrdList = BattleConst.GRID_OUT_LINE_POS_ID[findPodId] if not aounrdList then break end local got = false for id, status in pairs(aounrdList) do if posMap[id] and not self.findCanUseMap[id] and BattleBoardTouchHelper:judgeGridEdgeCanLink(findPodId, id) then table.insert(self.findCanLinkList, id) count = count + 1 self.findCanUseMap[id] = true findPodId = id got = true break end end if not got then break end if count >= needCount then gotPos = true break end end if gotPos then break end end return gotPos, self.findCanUseMap, self.findCanLinkList end function BattleBaseController: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 if #lineList >= self:getMinEliminationCount() then return hadSkill end local lineCount = 0 local maxLineList local maxPosIdMap local maxGotSkill for aroundposId, _ in pairs(list) do if self:getPosIdInCurActionBoardRowRange(aroundposId) and not posIdMap[aroundposId] and BattleBoardTouchHelper:judgeGridEdgeCanLink(posId, aroundposId) then local gridEntity = self.battleData:getGridEntity(aroundposId) if gridEntity then if gridEntity:canLink() and not gridEntity:getSkillId() 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:canLink() and gridEntity:getSkillId() and not hadSkill and mainElementType then local skillId = gridEntity:getSkillId() local skillEntity = self:getSkillEntityBySkillId(skillId) if skillEntity then if skillEntity:getIgnoreElementType() 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 BattleBaseController:generateMonsterById(monsterId, callback) local unitEntity = self.battleData:addMonster(monsterId, true, self) local modelId = unitEntity:getModelId() BattleHelper:loadBattleHeroModel(modelId, self.battleUI:getBattleNode(), function(spineObject) self.defTeam:removeAllUnits() local monsterComp = spineObject:addLuaComponent(GConst.BattleConst.TYPEOF_LUA_COMP.BATTLE_MONSTER_COMPONENT) monsterComp:initWithEntity(modelId, unitEntity, self) self.defTeam:addUnit(monsterComp, true) self.battleUI:refreshDefHp(unitEntity:getHp(), unitEntity:getHpPercent()) monsterComp:playEnterBattlefield(false, callback) end) end function BattleBaseController:addBattleExp(exp) if not self.battleData or not exp then return end self.battleData:addExp(exp) end function BattleBaseController:addTaskProgress(fieldName, count) if self:getCurActionSide() ~= SIDE_ATK then return end if not count then return end self.taskProgress[fieldName] = (self.taskProgress[fieldName] or 0) + count end function BattleBaseController:setTaskProgress(fieldName, count) if not count then return end self.taskProgress[fieldName] = count end function BattleBaseController:getTaskProgress() return self.taskProgress end function BattleBaseController:addFillWaitingCount() self.waitingFillCount = self.waitingFillCount + 1 end function BattleBaseController:reduceFillWaitingCount() self.waitingFillCount = self.waitingFillCount - 1 end function BattleBaseController:_tick(dt, originDt) self.realTime = self.realTime + dt self.waveDurationTime = self.waveDurationTime + originDt self.totalDurationTime = self.totalDurationTime + originDt if self.isPause then return end if self.needWaitingBoardOver == false then self:enterRoundBegin() end if self.waitingFillCount <= 0 and self.isWaitingFill and self.isRoundBeginCheck then self:fillBoard(self.isRoundBeginCheck) 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:checkDelayEffectText(dt) self:checkSkillSlowDown(dt) self:tick(dt) BattleBoardTouchHelper:tick(dt) end function BattleBaseController:battleEnd() if self.battleEndSid then ModuleManager.BattleManager:unscheduleGlobal(self.battleEndSid) self.battleEndSid = nil end self.battleUI:disableUITouch() self.battleEndSid = ModuleManager.BattleManager:performWithDelayGlobal(function() if self.battleUI then self.battleUI:enableUITouch() end -- 处理战斗任务 local curWaveIndex = self:getWaveIndex() if self.victory then self:setTaskProgress(GConst.BattleConst.BATTLE_TASK_FIELD.KILLS_BOSS_TURN, self.waveRoundCount[curWaveIndex]) end local teamEntity = self.battleData:getAtkTeam() local hpp = math.floor(teamEntity:getHpPercent() * 100 + 0.0001) self:setTaskProgress(GConst.BattleConst.BATTLE_TASK_FIELD.SPARE_HP, hpp) local totalRound = 0 for wave, round in pairs(self.waveRoundCount) do if wave == curWaveIndex then if self.victory then totalRound = totalRound + round end else totalRound = totalRound + round end end self:setTaskProgress(GConst.BattleConst.BATTLE_TASK_FIELD.TOTAL_TURN, totalRound) -- end处理战斗任务 self:controllBattleEnd() if self.victory then ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_BATTLE_VICTORY) end end, 1) end function BattleBaseController: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() BattlePool:clear() self:unBindAll() self.battleData:clear() self.battleData:resetTimeSpeed() ModuleManager.BattleManager:unscheduleAll() if DataManager.TutorialData:getIsInTutorial() then ModuleManager.TutorialManager:stopTutorial() end end function BattleBaseController:endBattleAndExit() BATTLE_SNAPSHOT_HELPER:clearSnap(self) ModuleManager.BattleManager:exitBattle() end function BattleBaseController:checkSkillSlowDown(dt) if self.skillSlowDownDuration == nil then return end self.skillSlowDownDuration = self.skillSlowDownDuration - dt if self.skillSlowDownDuration >= 0 then return end self.skillSlowDownDuration = nil self:resetTimeSpeed() end function BattleBaseController:checkDelayEffectText(dt) if self.delayEffectTextCount <= 0 then return end for i = self.delayEffectTextCount, 1, -1 do local delayEffectText = self.delayEffectTextList[i] delayEffectText.time = delayEffectText.time - dt if delayEffectText.time <= 0 then local effectTextComp = BattleHelper:getEffectText(self.battleUI:getNumberNode(), delayEffectText.colorType) effectTextComp:showEffectNumber(delayEffectText.effectType, delayEffectText.num, delayEffectText.x, delayEffectText.y, delayEffectText.showCombo) table.insert(self.effectTexts, effectTextComp) local tailDelayEffectText = self.delayEffectTextList[self.delayEffectTextCount] delayEffectText.colorType = tailDelayEffectText.colorType delayEffectText.effectType = tailDelayEffectText.effectType delayEffectText.num = tailDelayEffectText.num delayEffectText.x = tailDelayEffectText.x delayEffectText.y = tailDelayEffectText.y delayEffectText.time = tailDelayEffectText.time delayEffectText.showCombo = tailDelayEffectText.showCombo self.delayEffectTextCount = self.delayEffectTextCount - 1 end end end function BattleBaseController:showEffectNumber(colorType, effectType, num, x, y, delayTime, showCombo) if delayTime > 0 then self.delayEffectTextCount = self.delayEffectTextCount + 1 local obj = self.delayEffectTextList[self.delayEffectTextCount] if obj == nil then obj = {} self.delayEffectTextList[self.delayEffectTextCount] = obj end obj.colorType = colorType obj.effectType = effectType obj.num = num obj.x = x obj.y = y obj.time = delayTime obj.showCombo = showCombo else local effectTextComp = BattleHelper:getEffectText(self.battleUI:getNumberNode(), colorType) effectTextComp:showEffectNumber(effectType, num, x, y, showCombo) table.insert(self.effectTexts, effectTextComp) end end function BattleBaseController:getFxNode() return self.battleUI:getFxNode() end function BattleBaseController:shakeScreen(shakeType, duration) self.battleUI:shakeScreen(shakeType, duration) end local function _addCurRoundAttr(self, side, instruction, callback) if instruction.effectList then local defComp = self.defTeam:getMainUnit() local atkComp = self.atkTeam:getMainUnit() local isAtkSide = side == SIDE_ATK local actionComp = isAtkSide and atkComp or defComp for _, effect in ipairs(instruction.effectList) do local target if effect:getTargetSide() == BattleConst.SIDE_DEF then target = isAtkSide and defComp or atkComp elseif effect:getTargetSide() == BattleConst.SIDE_ATK then target = isAtkSide and atkComp or defComp else local matchType = BattleConst.SIDE_OBJ_TO_MATCH_TYPE[effect:getTargetSide()] if matchType then if isAtkSide then target = self.atkTeam:getUnitComp()[matchType] else target = self.defTeam:getUnitComp()[matchType] end end end if target then actionComp:takeEffect(effect, target) end end end callback() end local function _assisting(self, side, instruction, callback) local actionTeam = self.atkTeam if side == SIDE_DEF then actionTeam = self.defTeam end actionTeam:useAssistingSkill(instruction.assistingList, #self.instructions == 0, callback) end local function _generalAttack(self, side, instruction, callback) local actionTeam = self.atkTeam if side == SIDE_DEF then actionTeam = self.defTeam end actionTeam:useNormalSkill(instruction.skillMatch, instruction.count, #self.instructions == 0, BattleConst.EFFECT_TYPE.DIRECT, BattleConst.ATTACK_ACTION_STATE.NORMAL, callback) end local function _playSkill(self, side, instruction, callback) local actionTeam = self.atkTeam if side == SIDE_DEF then actionTeam = self.defTeam end actionTeam:useSkill(instruction.skillMatch, instruction.count, #self.instructions == 0, BattleConst.EFFECT_TYPE.DIRECT, BattleConst.ATTACK_ACTION_STATE.NORMAL, callback) end BattleBaseController._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, } function BattleBaseController:calExpectedInjury(mainElementType, count, skillId) local atkCompMap = self:getCurActionTeam():getUnitComp() if not atkCompMap then return 0 end local atkUnitComp = atkCompMap[mainElementType] if mainElementType and not atkUnitComp then return 0 end if not mainElementType or not atkUnitComp then count = 0 atkUnitComp = self:getCurActionTeam():getMainUnit() end local dmg = BattleFormula:getExpectedDamageResult(atkUnitComp, count, self:getCurOtherActionUnitComp(), skillId, atkCompMap) return dmg end return BattleBaseController