require("Modules.Battle.Logic.HardStageCondition") require("Modules.Battle.Logic.HardStageEventManager") BattleLogic = {} local floor = math.floor local min = math.min -- local objList = BattleDictionary.New() local removeObjList = BattleList.New() local MaxRound = 20 local CurRound = 0 local CurCamp = 0 local CurSkillPos = {} local PosList = {} local curFrame BattleLogic.Type = -1 -- 0 切磋 1 故事副本 2 地图探索 3 竞技场 4 秘境boss 5 解锁秘境 6 公会战 7 血战 8 兽潮 9巅峰战 BattleLogic.IsEnd = false BattleLogic.Result = -1 BattleLogic.Event = BattleEvent.New() BattleLogic.BuffMgr = BuffManager.New() local _IsDebug local fightData local record local userData --所有英雄伤害和治疗 local allHeroDamage=0 --所有怪的伤害和治疗 local allEnemyDamage=0 --关卡星级记录 local levelStarRecord local hardStageId =0 local insertSkillRole=nil --是否开启战斗日志 BattleLogic.IsOpenBattleRecord = false --逻辑帧频 BattleLogic.GameFrameRate = 30 BattleLogic.GameDeltaTime = 1 / BattleLogic.GameFrameRate --总波次 BattleLogic.TotalOrder = 0 --当前波次 BattleLogic.CurOrder = 0 local actionPool = BattleObjectPool.New(function () return { 0, 0 } end) local tbActionList = BattleList.New() local rolePool = BattleObjectPool.New(function () return RoleLogic.New() end) function BattleLogic.Init(data, _userData, maxRound) if BattleLogic.IsOpenBattleRecord then record = {} end levelStarRecord={} fightData = data userData = _userData hardStageId=data.nodeId insertSkillRole=nil BattleLogic.CurOrder = 0 BattleLogic.TotalOrder = #data.enemyData BattleLogic.Clear() curFrame = 0 CurRound = 0 MaxRound = maxRound or 20 allHeroDamage= 0 allEnemyDamage= 0 _IsDebug = false BattleLogic.Event:ClearEvent() BattleLogic.BuffMgr:Init() BattleLogic.IsEnd = false BattleLogic.Result = -1 -- 日志管理放到前面初始化 BattleLogManager.Init(fightData, userData, maxRound) MonsterManager.Init() RoleManager.Init() SkillManager.Init() OutDataManager.Init(fightData) PassiveManager.Init() HardStageEventManager.Init() -- 监听英雄受到治疗 BattleLogic.Event:AddEvent(BattleEventName.RoleBeTreated,function (castRole, realTreat, treat) --巅峰争霸赛和切磋超时改为只判断总伤害,不再判断总治疗 -- if castRole.camp==0 then -- allHeroDamage=allHeroDamage+treat -- else -- allEnemyDamage=allEnemyDamage+treat -- end end) --监听英雄受到攻击 BattleLogic.Event:AddEvent(BattleEventName.RoleBeDamaged,function (defRole, atkRole, damage, bCrit, finalDmg, damageType, dotType) --我方阵营总攻击 if atkRole.camp==0 then allHeroDamage=allHeroDamage+damage --敌方阵营 else allEnemyDamage=allEnemyDamage+damage end end) end --获取是否为pvp战斗 function BattleLogic.GetIsPvP() if BattleLogic.Type== BATTLE_SERVER_TYPE.TOPFight or BattleLogic.Type== BATTLE_SERVER_TYPE.Firend or BattleLogic.Type== BATTLE_SERVER_TYPE.ArenaFight or BattleLogic.Type== BATTLE_SERVER_TYPE.CarPersonFight or BattleLogic.Type== BATTLE_SERVER_TYPE.CrossYuxuLunDaoFight or BattleLogic.Type== BATTLE_SERVER_TYPE.NewArenaFight or BattleLogic.Type== BATTLE_SERVER_TYPE.LINGMAIMIJING then return true end return false end -- 获取双方所有血量 function BattleLogic.GetAllDamage() return allHeroDamage, allEnemyDamage end --获取我方灵兽数据 function BattleLogic.GetPlayerMonsterData() return fightData.playerData.monsterList end --获取精英副本星级记录 function BattleLogic.GetHardLevelStarRecord() return levelStarRecord end -- 检测先手阵营 function BattleLogic.CheckFirstCamp() -- 默认我方先手 BattleLogic.FirstCamp = 0 -- 数据不存在时,兼容老战斗数据 if not fightData.playerData.firstCamp and not fightData.enemyData[BattleLogic.CurOrder].firstCamp then return end -- 敌方先手 if fightData.playerData.firstCamp == 0 and fightData.enemyData[BattleLogic.CurOrder].firstCamp == 1 then BattleLogic.FirstCamp = 1 end end function BattleLogic.InitOrder() BattleLogic.CurOrder = BattleLogic.CurOrder + 1 if BattleLogic.CurOrder == 1 then local playerData = fightData.playerData local enemyData = fightData.enemyData[BattleLogic.CurOrder] for i=1, #playerData do RoleManager.AddRole(playerData[i], playerData[i].position) end for i=1, #enemyData do RoleManager.AddRole(enemyData[i], enemyData[i].position) end local playerMonsterList = fightData.playerData.monsterList if playerMonsterList then for i=1, #playerMonsterList do MonsterManager.AddMonster(playerMonsterList[i]) end end local enemyMonsterList = fightData.enemyData[1].monsterList if enemyMonsterList then for i=1, #enemyMonsterList do MonsterManager.AddMonster(enemyMonsterList[i]) end end else RoleManager.ClearEnemy() local orderList = fightData.enemyData[BattleLogic.CurOrder] for i=1, #orderList do RoleManager.AddRole(orderList[i], orderList[i].position) end MonsterManager.ClearEnemy() local enemyMonsterList = orderList.monsterList if enemyMonsterList then for i=1, #enemyMonsterList do MonsterManager.AddMonster(enemyMonsterList[i]) end end end end function BattleLogic.StartTurnRound() BattleLogic.CheckFirstCamp()-- 检测先后手 BattleLogic.TurnRoundNextFrame()-- 开始战斗,延时一帧执行,避免战斗还没开始就释放了技能 BattleLogic.Event:DispatchEvent(BattleEventName.BattleStart)-- 战斗开始 end function BattleLogic.StartOrder() BattleLogic.InitOrder() BattleLogic.StartTurnRound() end -- 获取当前轮数 function BattleLogic.GetCurRound() -- body return CurRound, MaxRound end -- 获取当前轮次信息 function BattleLogic.GetCurTurn() -- body return CurCamp, CurSkillPos[CurCamp] end -- 设置是否是debug function BattleLogic.SetIsDebug(isDebug) _IsDebug = isDebug end function BattleLogic.GetIsDebug() return _IsDebug end -- 下一帧开始下一轮 local _TurnRoundFlag = 0 function BattleLogic.TurnRoundNextFrame() _TurnRoundFlag = 0 end -- 检测是否要轮转 function BattleLogic.CheckTurnRound() if _TurnRoundFlag == 2 then return end _TurnRoundFlag = _TurnRoundFlag + 1 if _TurnRoundFlag == 2 then BattleLogic.TurnRound() end end -- 开始轮转 -- debugTurn 用于判断是否是debug轮转的参数 function BattleLogic.TurnRound(debugTurn) if BattleLogic.GetIsDebug() and not debugTurn then BattleLogic.Event:DispatchEvent(BattleEventName.DebugStop) return end -- 第一次进入 或者 本轮结束 初始化流程状态 if CurRound == 0 or (CurSkillPos[0] == 6 and CurSkillPos[1] == 6) then if CurRound ~= 0 then if BattleLogic.CheckHaveInsertRole() then return else -- 上一轮结束 BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoundEnd, CurRound) end end -- 检测一次灵兽技能 SkillManager.CheckMonsterSkill(function() CurRound = CurRound + 1 CurCamp = BattleLogic.FirstCamp -- 判断先手阵营 CurSkillPos[0] = 0 CurSkillPos[1] = 0 -- BattleLogManager.Log( "Round Change", "round", CurRound ) -- 轮数变化 BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoundChange, CurRound) --刷新灵兽buff,回合开始前刷新,如果灵兽技能是在回合后释放,持续1回合,配置的回合数要+1 2020/12/05 by:王振兴 BattleLogic.BuffMgr:PassMonsterUpdate() -- 开始 BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoundStart, CurRound) -- 检测一次灵兽技能 SkillManager.CheckMonsterSkill(function() --轮数变化后延时0.2秒用于初始化监听回合数被动的初始化 BattleLogic.WaitForTrigger(0.5,function() -- 进入新轮 BattleLogic.CheckBattleLogic() end) end) end) else -- 检测一次灵兽技能 SkillManager.CheckMonsterSkill(function() --轮数变化后延时0.2秒用于初始化监听回合数被动的初始化 BattleLogic.WaitForTrigger(0.5,function() -- 切换阵营 if not insertSkillRole then CurCamp = (CurCamp + 1) % 2 end BattleLogic.CheckBattleLogic() end) end) end end --检测战斗逻辑 function BattleLogic.CheckBattleLogic() -- 这里再检测一次战斗结束 if CurRound > MaxRound then return end BattleLogManager.Log( "Camp Change", "camp", CurCamp ) -- 找到下一个释放技能的人 local SkillRole local lastPos --如果有插入行动的英雄,就先让插入的英雄行动 if insertSkillRole then SkillRole =insertSkillRole insertSkillRole=nil --记录下正常执行行动的英雄的位置,插入英雄行动完,再按照正常顺序执行 lastPos=CurSkillPos[CurCamp] CurSkillPos[CurCamp]=SkillRole.position -- 如果当前位置不能释放技能也需要走buff轮转 BattleLogic.BuffMgr:TurnUpdate(1) -- 计算恢复血量 BattleLogic.BuffMgr:TurnUpdate(2) -- 计算持续伤害(除去流血) BattleLogic.BuffMgr:TurnUpdate(3) -- 计算持续伤害(流血) BattleLogic.BuffMgr:TurnUpdate(4) -- 计算其他buff BattleLogic.BuffMgr:PassUpdate() -- 计算buff轮数 BattleLogic.BuffMgr:PassUpdateNoDead() -- 计算buff不灭 CurSkillPos[CurCamp]=lastPos end if not SkillRole then -- 当前阵营下一释放技能的位置 local cpos = CurSkillPos[CurCamp] + 1 for p = cpos, 6 do -- 保存当前位置 CurSkillPos[CurCamp] = p -- 自己阵营中的位置 + 自己阵营的ID * 6 = 自己在PosList中的位置 local role = RoleManager.GetRole(CurCamp, p) --PosList[p + (CurCamp * 6)] --角色如果被放逐不能行动 by:wangzhenxing 2020/12/23 11:35 if role and not role:IsRealDead() and not role.isExile then SkillRole = role break end -- 如果当前位置不能释放技能也需要走buff轮转 BattleLogic.BuffMgr:TurnUpdate(1) -- 计算恢复血量 BattleLogic.BuffMgr:TurnUpdate(2) -- 计算持续伤害(除去流血) BattleLogic.BuffMgr:TurnUpdate(3) -- 计算持续伤害(流血) BattleLogic.BuffMgr:TurnUpdate(4) -- 计算其他buff BattleLogic.BuffMgr:PassUpdate() -- 计算buff轮数 BattleLogic.BuffMgr:PassUpdateNoDead() -- 计算buff不灭 end end -- 如果找不到下一个人,直接交换阵营 if not SkillRole then BattleLogManager.Log( "No Skill Position" ) BattleLogic.TurnRoundNextFrame() return end -- BattleLogManager.Log( "Position Change", "position", CurSkillPos[CurCamp] ) -- 行动 SkillRole.Event:DispatchEvent(BattleEventName.RoleTurnStart, SkillRole) -- 开始行动 BattleLogic.Event:DispatchEvent(BattleEventName.RoleTurnStart, SkillRole) -- 开始行动 -- buff计算 BattleLogic.BuffMgr:TurnUpdate(1) -- 计算恢复血量 BattleLogic.BuffMgr:TurnUpdate(2) -- 计算持续伤害(除去流血) -- 设置行动完成回调 SkillManager.SetTurnRoundFunc(function() BattleLogic.BuffMgr:TurnUpdate(3) -- 计算持续伤害(流血) BattleLogic.BuffMgr:TurnUpdate(4) -- 计算其他buff BattleLogic.BuffMgr:PassUpdate() -- 计算buff轮数 BattleLogic.BuffMgr:PassUpdateNoDead() -- 计算buff不灭 SkillRole.Event:DispatchEvent(BattleEventName.RoleTurnEnd, SkillRole) -- 行动结束 BattleLogic.Event:DispatchEvent(BattleEventName.RoleTurnEnd, SkillRole) -- 开始行动 BattleLogic.TurnRoundNextFrame() end) -- 如果角色无法释放技能 if not SkillRole:IsAvailable() -- 角色不能释放技能 or (SkillRole:IsDead() -- 将死状态 and not BattleLogic.BuffMgr:HasBuff(SkillRole,BuffName.NoDead) --将死但没有不死buff and not SkillManager.HaveMySkill(SkillRole)) -- 也没有要释放的技能 then SkillManager.CheckTurnRound() return end -- 释放技能后,递归交换阵营 SkillRole:CastSkill() end --检测是否有插入得英雄 function BattleLogic.CheckHaveInsertRole() if insertSkillRole then local SkillRole=insertSkillRole insertSkillRole=nil -- 如果找不到下一个人,直接交换阵营 if not SkillRole then BattleLogManager.Log( "No Skill Position" ) BattleLogic.TurnRoundNextFrame() return end -- BattleLogManager.Log( "Position Change", "position", CurSkillPos[CurCamp] ) -- 行动 SkillRole.Event:DispatchEvent(BattleEventName.RoleTurnStart, SkillRole) -- 开始行动 BattleLogic.Event:DispatchEvent(BattleEventName.RoleTurnStart, SkillRole) -- 开始行动 -- buff计算 BattleLogic.BuffMgr:TurnUpdate(1) -- 计算恢复血量 BattleLogic.BuffMgr:TurnUpdate(2) -- 计算持续伤害(除去流血) -- 设置行动完成回调 SkillManager.SetTurnRoundFunc(function() BattleLogic.BuffMgr:TurnUpdate(3) -- 计算持续伤害(流血) BattleLogic.BuffMgr:TurnUpdate(4) -- 计算其他buff BattleLogic.BuffMgr:PassUpdate() -- 计算buff轮数 BattleLogic.BuffMgr:PassUpdateNoDead() -- 计算buff不灭 SkillRole.Event:DispatchEvent(BattleEventName.RoleTurnEnd, SkillRole) -- 行动结束 BattleLogic.Event:DispatchEvent(BattleEventName.RoleTurnEnd, SkillRole) -- 开始行动 BattleLogic.TurnRoundNextFrame() end) -- 如果角色无法释放技能 if not SkillRole:IsAvailable() -- 角色不能释放技能 or (SkillRole:IsDead() -- 将死状态 and not BattleLogic.BuffMgr:HasBuff(SkillRole,BuffName.NoDead) --将死但没有不死buff and not SkillManager.HaveMySkill(SkillRole)) -- 也没有要释放的技能 then SkillManager.CheckTurnRound() return end -- 释放技能后,递归交换阵营 SkillRole:CastSkill() return true else return false end end function BattleLogic.WaitForTrigger(delayTime, action) delayTime = BattleUtil.ErrorCorrection(delayTime) local delayFrame = floor(delayTime * BattleLogic.GameFrameRate + 0.5) if delayFrame == 0 then --0延迟的回调直接调用 action() return end local item = actionPool:Get() item[1] = curFrame + delayFrame item[2] = action tbActionList:Add(item) end function BattleLogic.InsertSkillRole(role) insertSkillRole=role end function BattleLogic.CurFrame() return curFrame end function BattleLogic.Update() curFrame = curFrame + 1 -- 强制退出 if curFrame > BattleMaxFrame then assert(false, "Battle Time Out !!!") BattleLogic.BattleEnd(-1) return end local roleResult = RoleManager.GetResult() if roleResult == 0 then BattleLogic.BattleEnd(0) return end if CurRound > MaxRound then if BattleLogic.Type == BATTLE_SERVER_TYPE.TOPFight -- 巅峰赛 or BattleLogic.Type == BATTLE_SERVER_TYPE.Firend or BattleLogic.Type == BATTLE_SERVER_TYPE.CrossYuxuLunDaoFight or BattleLogic.Type == BATTLE_SERVER_TYPE.LINGMAIMIJING or BattleLogic.Type == BATTLE_SERVER_TYPE.CarPersonFight or BattleLogic.Type == BATTLE_SERVER_TYPE.NewArenaFight then -- 好友切磋 if allHeroDamage>allEnemyDamage then BattleLogic.BattleEnd(1) else BattleLogic.BattleEnd(0) end else BattleLogic.BattleEnd(0) end return end if roleResult == 1 then if BattleLogic.CurOrder == BattleLogic.TotalOrder then BattleLogic.BattleEnd(1) else BattleLogic.Event:DispatchEvent(BattleEventName.BattleOrderChange, BattleLogic.CurOrder + 1) BattleLogic.StartOrder() end end -- 检测帧事件(技能命中,伤害计算,buff生成) local index = 1 while index <= tbActionList.size do local action = tbActionList.buffer[index] if action[1] <= curFrame then action[2]() actionPool:Put(action) tbActionList:Remove(index) else index = index + 1 end end -- 检测buff BattleLogic.BuffMgr:Update() --- -- 检测死亡 if RoleManager.CheckDead() then -- 单独用一帧执行死亡 return end -- 检测复活 if RoleManager.CheckRelive() then -- 单独用一帧执行复活 return end -- 没有技能释放时再检测轮转 if SkillManager.IsSkillEmpty() then -- 检测轮转 BattleLogic.CheckTurnRound() end -- 技能 SkillManager.Update() --如果有英雄有可以复活的技能,先执行技能逻辑,最后判断死亡人数 by:王振兴 -- 检测角色状态 RoleManager.Update() -- 检测灵兽状态 MonsterManager.Update() end -- 战斗结束 function BattleLogic.BattleEnd(result) -- BattleLogic.Event:DispatchEvent(BattleEventName.BeforeBattleEnd, result) -- BattleLogic.IsEnd = true BattleLogic.Result = result BattleLogic.Event:DispatchEvent(BattleEventName.BattleEnd, result) if hardStageId and hardStageId~=0 then --获取精英副本 星级信息 local hardStageConfig=ConfigManager.GetConfigData(ConfigName.HardStage,hardStageId) if hardStageConfig then if hardStageConfig.ConditionValue then for i = 1, #hardStageConfig.ConditionValue do local harConfig = ConfigManager.GetConfigData(ConfigName.HardStageCondition,hardStageConfig.ConditionValue[i]) local v1 = HardStageCondition.CheckCondition(harConfig.ConditionType,harConfig.ConditionValue) table.insert(levelStarRecord,hardStageConfig.ConditionValue[i]) table.insert(levelStarRecord,v1) end end end end -- 打印结果 BattleLogic.LogResult(result) -- 战斗日志写入 if not BattleLogic.GetIsDebug() then BattleLogManager.WriteLogToFile() end HardStageEventManager.ClearEvent() end -- 打印战斗结果 function BattleLogic.LogResult(result) local allHeroDamage, allEnemyDamage = BattleLogic.GetAllDamage() local heroHP = {0, 0, 0, 0, 0, 0} local arr = RoleManager.Query(function (r) return r.camp == 0 end, true) for i=1, #arr do local pos = arr[i].position heroHP[pos] = arr[i]:GetRoleData(RoleDataName.Hp) end local enemyHP = {0, 0, 0, 0, 0, 0} local arr = RoleManager.Query(function (r) return r.camp == 1 end, true) for i=1, #arr do local pos = arr[i].position enemyHP[pos] = arr[i]:GetRoleData(RoleDataName.Hp) end BattleLogManager.Log( "Battle Over!!!!!!!", "result", result, "allHeroDamage", allHeroDamage, "allEnemyDamage", allEnemyDamage, "duration", BattleLogic.CurFrame() / BattleLogic.GameFrameRate, "heroHP", BattleLogManager.PrintBattleTable(heroHP), "enemyHP", BattleLogManager.PrintBattleTable(enemyHP) ) end -- function BattleLogic.Clear() -- 清空角色 RoleManager.Clear() -- 清空事件 while tbActionList.size > 0 do actionPool:Put(tbActionList.buffer[tbActionList.size]) tbActionList:Remove(tbActionList.size) end end