miduo_client/Assets/ManagedResources/~Lua/Modules/Battle/Logic/BattleLogic.lua

675 lines
23 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
local insertSkillRoleList=nil
--是否开启战斗日志
BattleLogic.IsOpenBattleRecord = false
--逻辑帧频
BattleLogic.GameFrameRate = 30
BattleLogic.GameDeltaTime = 1 / BattleLogic.GameFrameRate
--总波次
BattleLogic.TotalOrder = 0
--当前波次
BattleLogic.CurOrder = 0
--当前回合触发总次数添加buff伤害治疗
local curRoundTriggerTime=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.AddRoundTriggerTime()
curRoundTriggerTime=curRoundTriggerTime+1
end
function BattleLogic.Init(data, _userData, maxRound)
if BattleLogic.IsOpenBattleRecord then
record = {}
end
levelStarRecord={}
fightData = data
userData = _userData
hardStageId=data.nodeId
insertSkillRole=nil
insertSkillRoleList={}
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)
RoleManager.Init()
MonsterManager.Init()
FightWeaponManager.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)
BattleLogic.Event:AddEvent(BattleEventName.BattleRoundChange,function()
curRoundTriggerTime=0
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 playerWeaPonList = fightData.playerData.weaponList
if playerWeaPonList then
for i=1, #playerWeaPonList do
--LogError("创建一个神兵")
FightWeaponManager.AddWeapon(playerWeaPonList[i])
end
end
local enemyMonsterList = fightData.enemyData[1].monsterList
if enemyMonsterList then
for i=1, #enemyMonsterList do
MonsterManager.AddMonster(enemyMonsterList[i])
end
end
local enemyWeaponList = fightData.enemyData[1].weaponList
if enemyWeaponList then
for i=1, #enemyWeaponList do
--LogError("创建一个神兵")
FightWeaponManager.AddWeapon(enemyWeaponList[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
FightWeaponManager.ClearEnemy()
local enemyWeaponList = orderList.weaponList
if enemyWeaponList then
for i=1, #enemyWeaponList do
--LogError("创建一个神兵")
FightWeaponManager.AddWeapon(enemyWeaponList[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.BattleRoundEndBefore, CurRound)
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 #insertSkillRoleList==0 and insertSkillRole==nil 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 insertSkillRoleList and #insertSkillRoleList>0 then
insertSkillRole=insertSkillRoleList[1]
SkillRole =insertSkillRole
table_removebyvalue(insertSkillRoleList,insertSkillRole)
--table.removebyvalue(insertSkillRoleList,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
-- 释放技能后,递归交换阵营
--RoleLogic
SkillRole:CastSkill()
end
--检测是否有插入得英雄
function BattleLogic.CheckHaveInsertRole()
if insertSkillRoleList and #insertSkillRoleList>0 then
insertSkillRole=insertSkillRoleList[1]
local SkillRole=insertSkillRole
--table.removebyvalue(insertSkillRoleList,insertSkillRole)
table_removebyvalue(insertSkillRoleList,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
--LogError("curFrame"..curFrame+delayFrame)
item[2] = action
tbActionList:Add(item)
end
function BattleLogic.InsertSkillRole(role)
table.insert(insertSkillRoleList,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
if curRoundTriggerTime>2000 then
--assert(false, "Battle Round Time Out !!!")
BattleLogic.BattleEnd(-2)
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.ArenaFight
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]()
-- LogError("执行帧位"..action[1])
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()
MSkillManager.Clear()
-- 清空事件
while tbActionList.size > 0 do
actionPool:Put(tbActionList.buffer[tbActionList.size])
tbActionList:Remove(tbActionList.size)
end
end