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 curUid local curBuffId local curFrame local playerSkillUsable local enemySkillUsable local bMyAllDead local bEnemyAllDead BattleLogic.Type = 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 playerTeamDummyRole = {camp = 0, Event = BattleEvent.New(), isTeam = true, curSkill = nil, isDebug = false} local enemyTeamDummyRole = {camp = 1, Event = BattleEvent.New(), isTeam = true, curSkill = nil, isDebug = false} local playerTeamSkillList = {} local enemyTeamSkillList = {} local _IsDebug local fightData local record local optionRecord --是否开启战斗日志 BattleLogic.IsOpenBattleRecord = false --逻辑帧频 BattleLogic.GameFrameRate = 30 BattleLogic.GameDeltaTime = 1 / BattleLogic.GameFrameRate --总波次 BattleLogic.TotalOrder = 0 --当前波次 BattleLogic.CurOrder = 0 local teamSkillCastRound = {2, 4, 6} local MyTeamSkillCastIndex local EnemyTeamSkillCastIndex -- local maxFrame --战斗最大用时,超时判负 local actionPool = BattleObjectPool.New(function () return { 0, 0 } end) local skillPool = BattleObjectPool.New(function () return Skill:New() end) local tbActionList = BattleList.New() local rolePool = BattleObjectPool.New(function () return RoleLogic.New() end) function BattleLogic.Init(data, optionData) if BattleLogic.IsOpenBattleRecord then record = {} end -- maxFrame = BattleLogic.GameFrameRate * maxTime fightData = data if optionData then optionRecord = optionData else optionRecord = {} end BattleLogic.CurOrder = 0 BattleLogic.TotalOrder = #data.enemyData BattleLogic.Clear() curUid = 0 curBuffId = 0 curFrame = 0 CurRound = 0 _IsDebug = false playerTeamDummyRole.isDebug = false playerTeamDummyRole.Event:ClearEvent() enemyTeamDummyRole.isDebug = false enemyTeamDummyRole.Event:ClearEvent() playerSkillUsable = true enemySkillUsable = true bMyAllDead = false bEnemyAllDead = false BattleLogic.Event:ClearEvent() BattleLogic.BuffMgr:Init() BattleLogic.IsEnd = false BattleLogic.Result = -1 end function BattleLogic.StartOrder() -- BattleLogic.CurOrder = BattleLogic.CurOrder + 1 if BattleLogic.CurOrder == 1 then MyTeamSkillCastIndex = 1 EnemyTeamSkillCastIndex = 1 local playerData = fightData.playerData local enemyData = fightData.enemyData[BattleLogic.CurOrder] for i=1, #playerData do BattleLogic.AddRole(playerData[i], playerData[i].position) end for i=1, #enemyData do BattleLogic.AddRole(enemyData[i], enemyData[i].position) end for i=1,3 do if playerTeamSkillList[i] then skillPool:Put(playerTeamSkillList[i]) playerTeamSkillList[i]=nil end end for i=1, #playerData.teamSkill do local skill = skillPool:Get() skill:Init(playerTeamDummyRole, playerData.teamSkill[i], 0) playerTeamSkillList[i] = skill end for i=1, #playerData.teamPassive do for j=1, #playerData.teamPassive[i] do local v = playerData.teamPassive[i][j] local id = v[1] local args = {} for k = 2, #v do args[k-1] = v[k] end BattleLogic.TakeTeamPassivity(playerTeamDummyRole, id, args) end end for i=1,3 do if enemyTeamSkillList[i] then skillPool:Put(enemyTeamSkillList[i]) enemyTeamSkillList[i]=nil end end for i=1, #enemyData.teamSkill do local skill = skillPool:Get() skill:Init(enemyTeamDummyRole, enemyData.teamSkill[i], 0) enemyTeamSkillList[i] = skill end for i=1, #enemyData.teamPassive do for j=1, #enemyData.teamPassive[i] do local v = enemyData.teamPassive[i][j] local id = v[1] local args = {} for k = 2, #v do args[k-1] = v[k] end BattleLogic.TakeTeamPassivity(enemyTeamDummyRole, id, args) end end else BattleLogic.ClearOrder() local orderList = fightData.enemyData[BattleLogic.CurOrder] for i=1, #orderList do BattleLogic.AddRole(orderList[i], orderList[i].position) end for i=1, #enemyTeamSkillList do skillPool:Put(enemyTeamSkillList[i]) enemyTeamSkillList[i]=nil end for i=1, #orderList.teamSkill do local skill = skillPool:Get() skill:Init(enemyTeamDummyRole, orderList.teamSkill[i], 0) enemyTeamSkillList[i] = skill end for i=1, #orderList.teamPassive do for j=1, #orderList.teamPassive[i] do local v = orderList.teamPassive[i][j] local id = v[1] local args = {} for k = 2, #v do args[k-1] = v[k] end BattleLogic.TakeTeamPassivity(enemyTeamDummyRole, id, args) end end end -- 开始战斗,延时一帧执行,避免战斗还没开始就释放了技能 BattleLogic.WaitForTrigger(BattleLogic.GameDeltaTime, function() -- 开始战斗 BattleLogic.TurnRound() end) 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 -- 开始轮转 -- 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 CurRound = CurRound + 1 CurCamp = 0 CurSkillPos[0] = -1 -- 先从异妖开始检测 CurSkillPos[1] = -1 -- 轮数变化 BattleLogic.Event:DispatchEvent(BattleEventName.BattleRoundChange, CurRound) else -- 切换阵营 CurCamp = (CurCamp + 1) % 2 end -- 当前阵营下一释放技能的位置 local cpos = CurSkillPos[CurCamp] + 1 if cpos == 0 then -- 保存当前释放技能的位置 CurSkillPos[CurCamp] = cpos -- 检测异妖技能释放 BattleLogic.CheckTeamSkillCast(CurCamp) else -- 找到下一个释放技能的人 local SkillRole for p = cpos, 6 do -- 保存当前位置 CurSkillPos[CurCamp] = p -- 自己阵营中的位置 + 自己阵营的ID * 6 = 自己在PosList中的位置 local role = PosList[p + (CurCamp * 6)] if role and role:IsAvailable() then SkillRole = role break end -- 如果当前位置不能释放技能也需要走buff轮转 BattleLogic.BuffMgr:TurnUpdate(1) -- 计算恢复血量 BattleLogic.BuffMgr:TurnUpdate(2) -- 计算持续伤害(除去流血) BattleLogic.BuffMgr:TurnUpdate(3) -- 计算持续伤害(流血) BattleLogic.BuffMgr:TurnUpdate(4) -- 计算其他buff end -- 如果找不到下一个人,直接交换阵营 if not SkillRole then BattleLogic.TurnRound() return end SkillRole.Event:DispatchEvent(BattleEventName.RoleTurnStart) BattleLogic.BuffMgr:TurnUpdate(1) -- 计算恢复血量 BattleLogic.BuffMgr:TurnUpdate(2) -- 计算持续伤害(除去流血) -- 释放技能后,递归交换阵营 SkillRole:CastSkill(function() BattleLogic.BuffMgr:TurnUpdate(3) -- 计算持续伤害(流血) BattleLogic.BuffMgr:TurnUpdate(4) -- 计算其他buff SkillRole.Event:DispatchEvent(BattleEventName.RoleTurnEnd) BattleLogic.TurnRound() end) end end -- 触发异妖被动 function BattleLogic.TakeTeamPassivity(teamCaster, id, args) for _, v in pairs(PosList) do BattleUtil.Passivity[id](v, args) end -- objList:Foreach(function(k, v) -- BattleUtil.Passivity[id](v, args) -- end) end -- 获取当前等待释放技能的异妖的序号 function BattleLogic.GetTeamSkillCastIndex(camp) -- body if camp == 0 then return MyTeamSkillCastIndex else return EnemyTeamSkillCastIndex end end -- 获取异妖 function BattleLogic.GetTeamSkill(camp, pos) if camp == 0 then return playerTeamSkillList[pos] else return enemyTeamSkillList[pos] end end -- 获取异妖技能CD function BattleLogic.GetTeamSkillCastSlider(camp) local teamSkillCastIndex = BattleLogic.GetTeamSkillCastIndex(camp) if playerTeamDummyRole.isDebug or teamSkillCastIndex > #teamSkillCastRound then return 0 end local slider = 0 if teamSkillCastIndex == 1 then slider = CurRound / teamSkillCastRound[teamSkillCastIndex] else slider = (CurRound - teamSkillCastRound[teamSkillCastIndex - 1]) / (teamSkillCastRound[teamSkillCastIndex] - teamSkillCastRound[teamSkillCastIndex - 1]) end return slider end -- 检测异妖技能是否可以释放 function BattleLogic.CheckTeamSkillCast(camp) local teamSkillCastIndex = BattleLogic.GetTeamSkillCastIndex(camp) local teamSkillList = camp == 0 and playerTeamSkillList or enemyTeamSkillList if teamSkillList[teamSkillCastIndex] then if teamSkillCastIndex <= #teamSkillCastRound and CurRound >= teamSkillCastRound[teamSkillCastIndex] then teamSkillList[teamSkillCastIndex]:Cast(BattleLogic.TurnRound) if camp == 0 then MyTeamSkillCastIndex = MyTeamSkillCastIndex + 1 else EnemyTeamSkillCastIndex = EnemyTeamSkillCastIndex + 1 end return end end -- 没有要释放技能的异妖,切换阵营 BattleLogic.TurnRound() end function BattleLogic.GenerateBuffId() if not curBuffId then curBuffId = 0 end curBuffId = curBuffId + 1 return curBuffId end -- 角色数据添加 function BattleLogic.AddRole(roleData, position) if not curUid then curUid = 0 end curUid = curUid + 1 local role = rolePool:Get() role:Init(curUid, roleData, position) -- objList:Add(curUid, role) if roleData.camp == 0 then PosList[position] = role -- 1-6 我方英雄 else PosList[position + 6] = role-- 7-12 敌方英雄 end if not role.isDead then BattleLogic.Event:DispatchEvent(BattleEventName.AddRole, role) end end -- 获取角色数据 function BattleLogic.GetRole(camp, pos) return PosList[pos + camp*6] end -- 获取某阵营所有角色 function BattleLogic.GetRoleByCamp(camp) local list = {} for i = 1, 6 do list[i] = PosList[i + camp * 6] end return list end function BattleLogic.SetSkillUsable(camp, value) if camp == 0 then playerSkillUsable = value else enemySkillUsable = value end end function BattleLogic.GetSkillUsable(camp) if camp == 0 then return playerSkillUsable else return enemySkillUsable 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) if BattleLogic.IsOpenBattleRecord then BattleLogic.RecordDelayTrigger(delayTime, curFrame + delayFrame) end end function BattleLogic.AddOption(opType, opArg) table.insert(optionRecord, {curFrame + 1, opType, opArg}) end function BattleLogic.GetTeamSkillCaster(camp) return camp == 0 and playerTeamDummyRole or enemyTeamDummyRole end function BattleLogic.CurFrame() return curFrame end function BattleLogic.Query(func, inCludeDeadRole) local list = {} local index = 1 if func then for pos, v in pairs(PosList) do if func(v) and (inCludeDeadRole or not v.isDead) then list[index] = v index = index + 1 end end -- objList:Foreach(function(k, v) -- if func(v) and (inCludeDeadRole or not v.isDead) then -- list[index] = v -- index = index + 1 -- end -- end) end return list end function BattleLogic.BattleEnd(result) BattleLogic.IsEnd = true BattleLogic.Result = result BattleLogic.Event:DispatchEvent(BattleEventName.BattleEnd, result) end function BattleLogic.Clear() -- while objList.size > 0 do -- objList.vList[objList.size]:Dispose() -- removeObjList:Add(objList.vList[objList.size]) -- objList:Remove(objList.vList[objList.size].uid) -- end for _, obj in pairs(PosList) do obj:Dispose() removeObjList:Add(obj) end PosList = {} while removeObjList.size > 0 do rolePool:Put(removeObjList.buffer[removeObjList.size]) removeObjList:Remove(removeObjList.size) end while tbActionList.size > 0 do actionPool:Put(tbActionList.buffer[tbActionList.size]) tbActionList:Remove(tbActionList.size) end end function BattleLogic.ClearOrder() local removePos = {} for pos, obj in pairs(PosList) do if obj.camp == 1 then removePos[pos] = 1 BattleLogic.Event:DispatchEvent(BattleEventName.RemoveRole, obj) obj:Dispose() removeObjList:Add(obj) end end for pos, _ in pairs(removePos) do PosList[pos] = nil end -- local index = 1 -- while index <= objList.size do -- if objList.vList[index].camp == 1 then -- BattleLogic.Event:DispatchEvent(BattleEventName.RemoveRole, objList.vList[index]) -- objList.vList[index]:Dispose() -- removeObjList:Add(objList.vList[index]) -- objList:Remove(objList.vList[index].uid) -- else -- index = index + 1 -- end -- end end function BattleLogic.Update() curFrame = curFrame + 1 -- if curFrame > maxFrame then -- BattleLogic.BattleEnd(0) -- return -- end if bMyAllDead then BattleLogic.BattleEnd(0) return end if CurRound > 20 then BattleLogic.BattleEnd(0) return end if bEnemyAllDead then if BattleLogic.CurOrder == BattleLogic.TotalOrder then BattleLogic.BattleEnd(1) else BattleLogic.Event:DispatchEvent(BattleEventName.BattleOrderChange, BattleLogic.CurOrder + 1) BattleLogic.StartOrder() end end 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 BattleLogic.BuffMgr:Update() bMyAllDead = true bEnemyAllDead = true for _, v in pairs(PosList) do if not v.isDead then v:Update() if v.camp == 0 then bMyAllDead = false else bEnemyAllDead = false end end end -- objList:Foreach(function(k, v) -- if not v.isDead then -- v:Update() -- if v.camp == 0 then -- bMyAllDead = false -- else -- bEnemyAllDead = false -- end -- end -- end) if bEnemyAllDead then BattleLogic.Event:DispatchEvent(BattleEventName.BattleOrderEnd, BattleLogic.CurOrder) end end --对位规则: 1敌方相同对位 2若死亡或不存在,选取相邻阵位最近且阵位索引最小的 function BattleLogic.GetAggro(role) -- 计算开始位置 local startPos = role.position startPos = startPos > 3 and startPos - 3 or startPos local target local enemyCamp = role.camp == 0 and 1 or 0 -- c=0 前排 c=1 后排 for c = 0, 1 do startPos = startPos + c*3 -- 向左 for i = startPos, c*3+1, -1 do local pos = i + enemyCamp * 6 if PosList[pos] and not PosList[pos].isDead then target = PosList[pos] break end end if target then return target end -- 向右 for i = startPos + 1, c*3+3 do local pos = i + enemyCamp * 6 if PosList[pos] and not PosList[pos].isDead then target = PosList[pos] break end end if target then return target end end end --对位规则: 1敌方相同对位 2若死亡或不存在,选取相邻阵位最近且阵位索引最小的 function BattleLogic.GetArrAggroList(role, arr) -- 重构数据 local plist = {} for _, role in ipairs(arr) do plist[role.position] = role end -- 计算开始位置 local startPos = role.position startPos = startPos > 3 and startPos - 3 or startPos local targetList = {} -- c=0 前排 c=1 后排 for c = 0, 1 do startPos = startPos + c*3 -- 向左 for i = startPos, c*3+1, -1 do local pos = i if plist[pos] and not plist[pos].isDead then table.insert(targetList, plist[pos]) end end -- 向右 for i = startPos + 1, c*3+3 do local pos = i if plist[pos] and not plist[pos].isDead then table.insert(targetList, plist[pos]) end end end return targetList end --获取对位相邻站位的人 chooseType 1 我方 2 敌方(对位的敌人受到嘲讽的影响,若对位的敌人死亡,则选取相邻最近的作为目标) function BattleLogic.GetNeighbor(role, chooseType) local posList = {} local target if chooseType == 1 then target = role else if role.lockTarget and not role.lockTarget.isDead then target = role.lockTarget else target = BattleLogic.GetAggro(role) end end if target then local list = BattleLogic.Query(function (r) return r.camp == target.camp end) for i=1, #list do if not list[i].isDead then if list[i].position == target.position + 3 -- 后排的人 or list[i].position == target.position - 3 -- 前排的人 or math.abs(target.position - list[i].position) <= 1 then -- 旁边的人和自己 table.insert(posList, list[i]) end end end end return posList end function BattleLogic.CastTeamSkill(camp) if camp == 0 then local teamSkill = playerTeamSkillList[MyTeamSkillCastIndex] if teamSkill then teamSkill:Cast() end else local teamSkill = enemyTeamSkillList[EnemyTeamSkillCastIndex] if teamSkill then teamSkill:Cast() end end end --Debug专用 -- function BattleLogic.SetDebug() -- objList:Foreach(function(k, v) -- v.IsDebug = not v.IsDebug -- end) -- playerTeamDummyRole.isDebug = not playerTeamDummyRole.isDebug -- enemyTeamDummyRole.isDebug = not enemyTeamDummyRole.isDebug -- end --Debug专用 -- function BattleLogic.SetRoleValue(uid, name, value) -- if objList.kvList[uid] then -- objList.kvList[uid].data:SetValue(name, value) -- end -- end -- --Debug专用 -- function BattleLogic.SetRoleDebug(uid, isDebug) -- if objList.kvList[uid] then -- objList.kvList[uid].IsDebug = isDebug -- end -- end --Record专用 function BattleLogic.GetRecord() return record end --Record专用 function BattleLogic.RecordSeed(seed) table.insert(record, string.format("frame:%d, seed:%d", curFrame, seed)) end --Record专用 function BattleLogic.RecordRoleProperty(uid, camp, name, value, delta) table.insert(record, string.format("frame:%d, uid:%d, camp:%d, name:%s, value:%d, delta:%d", curFrame, uid, camp, name, value, delta)) end --Record专用 function BattleLogic.RecordMul(args) local str = "" for i=1, #args do str = str..tostring(args[i]) .. (i == #args and "" or "#") end table.insert(record, string.format("frame:%d, mulArgs:%s", curFrame, str)) end --Record专用 function BattleLogic.RecordEffect(caster, target, type, args, interval) local cUid = tostring(caster.uid) or "cTeam" local tUid = tostring(target.uid) or "tTeam" local str = "" for i=1, #args do str = str..tostring(args[i]) .. (i == #args and "" or "#") end table.insert(record, string.format("frame:%d, caster:%s, target:%s, effectType:%d, args:%s, interval:%d", curFrame, cUid, tUid, type, str, interval)) end --Record专用 function BattleLogic.RecordDelayTrigger(delayFrame, triggerFrame) table.insert(record, string.format("frame:%d, delayTime:%f, triggerFrame:%d", curFrame, delayFrame, triggerFrame)) end --Record专用 function BattleLogic.GenerateRecordFile() local time = string.format("%d-%d-%d-%d-%d-%d", os.date("%Y"), os.date("%m"), os.date("%d"), os.date("%H"), os.date("%M"), os.date("%S")) local file = io.open("BattleRecord/"..time..".txt", "a") for i=1, #record do file:write(record[i].."\n") end io.close(file) end