BattleLogic = {} local floor = math.floor local min = math.min local objList = BattleDictionary.New() local removeObjList = BattleList.New() local curUid local curBuffId local curFrame local playerMP local enemyMP local playerSkillUsable local enemySkillUsable local isAuto BattleLogic.Type = 0 --1 故事副本 2 地图探索 3 竞技场 4 秘境boss 5 解锁秘境 6 公会战 7 血战 BattleLogic.IsEnd = false BattleLogic.Result = -1 BattleLogic.Event = BattleEvent.New() BattleLogic.BuffMgr = BuffManager.New() local skillManualQueue = BattleQueue.New() local playerTeamDummyRole = {camp = 0, Event = BattleLogic.Event, isTeam = true, curSkill = nil, isDebug = false} local enemyTeamDummyRole = {camp = 1, Event = BattleLogic.Event, isTeam = true, curSkill = nil, isDebug = false} local playerTeamSkillList = {} local enemyTeamSkillList = {} local playerTeamSkillIndex local enemyTeamSkillIndex local fightData local record local optionRecord --是否开启战斗日志 BattleLogic.IsOpenBattleRecord = false --逻辑帧频 BattleLogic.GameFrameRate = 30 BattleLogic.GameDeltaTime = 1 / BattleLogic.GameFrameRate --总波次 BattleLogic.TotalOrder = 0 --当前波次 BattleLogic.CurOrder = 0 local stage --战场分割阶段 local stageFrame1 = 25 * BattleLogic.GameFrameRate --前期转中期的时间点 local stageFrame2 = 40 * BattleLogic.GameFrameRate --中期转后期的时间点 local teamSkillCastTime = {15 * BattleLogic.GameFrameRate, 35 * BattleLogic.GameFrameRate, 55 * BattleLogic.GameFrameRate} local teamSkillCastIndex 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(maxTime, 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() skillManualQueue:Clear() curUid = 0 curBuffId = 0 curFrame = 0 playerMP = 0 enemyMP = 0 stage = 0 playerTeamDummyRole.isDebug = false enemyTeamDummyRole.isDebug = false playerSkillUsable = true enemySkillUsable = true isAuto = true BattleLogic.Event:ClearEvent() BattleLogic.BuffMgr:Init() BattleLogic.IsEnd = false BattleLogic.Result = -1 end function BattleLogic.StartOrder() BattleLogic.CurOrder = BattleLogic.CurOrder + 1 stage = 1 teamSkillCastIndex = 1 playerTeamSkillIndex = 1 enemyTeamSkillIndex = 1 curFrame = 0 BattleLogic.Event:DispatchEvent(BattleEventName.BattleStageChange, stage) if BattleLogic.CurOrder == 1 then for i=1, #fightData.playerData do BattleLogic.AddRole(fightData.playerData[i], i) end for i=1, #fightData.enemyData[BattleLogic.CurOrder] do BattleLogic.AddRole(fightData.enemyData[BattleLogic.CurOrder][i], i) end for i=1, #playerTeamSkillList do skillPool:Put(playerTeamSkillList[i]) playerTeamSkillList[i]=nil end for i=1, #fightData.playerData.teamSkill do playerTeamSkillList[i] = skillPool:Get() playerTeamSkillList[i]:Init(playerTeamDummyRole, fightData.playerData.teamSkill[i], 0) end for i=1, #fightData.playerData.teamPassive do for j=1, #fightData.playerData.teamPassive[i] do local v = fightData.playerData.teamPassive[i][j] local id = v[1] local args = {} for k = 2, #v do args[k-1] = v[k] end BattleUtil.Passivity[id](playerTeamDummyRole, args) end end for i=1, #enemyTeamSkillList do skillPool:Put(enemyTeamSkillList[i]) enemyTeamSkillList[i]=nil end for i=1, #fightData.enemyData[BattleLogic.CurOrder].teamSkill do enemyTeamSkillList[i] = skillPool:Get() enemyTeamSkillList[i]:Init(enemyTeamDummyRole, fightData.enemyData[BattleLogic.CurOrder].teamSkill[i], 0) end for i=1, #fightData.enemyData[BattleLogic.CurOrder].teamPassive do for j=1, #fightData.enemyData[BattleLogic.CurOrder].teamPassive[i] do local v = fightData.enemyData[BattleLogic.CurOrder].teamPassive[i][j] local id = v[1] local args = {} for k = 2, #v do args[k-1] = v[k] end BattleUtil.Passivity[id](enemyTeamDummyRole, args) end end else BattleLogic.ClearOrder() for i=1, #fightData.enemyData[BattleLogic.CurOrder] do BattleLogic.AddRole(fightData.enemyData[BattleLogic.CurOrder][i], i) end for i=1, #enemyTeamSkillList do skillPool:Put(enemyTeamSkillList[i]) enemyTeamSkillList[i]=nil end for i=1, #fightData.enemyData[BattleLogic.CurOrder].teamSkill do enemyTeamSkillList[i] = skillPool:Get() enemyTeamSkillList[i]:Init(enemyTeamDummyRole, fightData.enemyData[BattleLogic.CurOrder].teamSkill[i], 0) end for i=1, #fightData.enemyData[BattleLogic.CurOrder].teamPassive do for j=1, #fightData.enemyData[BattleLogic.CurOrder].teamPassive[i] do local v = fightData.enemyData[BattleLogic.CurOrder].teamPassive[i][j] local id = v[1] local args = {} for k = 2, #v do args[k-1] = v[k] end BattleUtil.Passivity[id](enemyTeamDummyRole, args) end end end end function BattleLogic.AddMP(camp, mp) --if camp == 0 then -- if #playerTeamSkillList > 0 then -- playerMP = min(playerMP + mp, 100) -- end --else -- if #enemyTeamSkillList > 0 then -- enemyMP = min(enemyMP + mp, 100) -- end --end end function BattleLogic.GetMP(camp) return camp == 0 and playerMP or enemyMP end function BattleLogic.CanManualTeamSkill() local teamSkill = playerTeamSkillList[playerTeamSkillIndex] return not isAuto and teamSkill end function BattleLogic.GetTeamSkillCastTime() if teamSkillCastIndex > #playerTeamSkillList then return -1 end return teamSkillCastTime[teamSkillCastIndex] - curFrame end function BattleLogic.GenerateBuffId() curBuffId = curBuffId + 1 return curBuffId end function BattleLogic.AddRole(roleData, position) curUid = curUid + 1 local role = rolePool:Get() role:Init(curUid, roleData, position) objList:Add(curUid, role) if not role.isDead then BattleLogic.Event:DispatchEvent(BattleEventName.AddRole, role) end 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.GetOption() return optionRecord end function BattleLogic.GetTeamSkillCaster(camp) return camp == 0 and playerTeamDummyRole or enemyTeamDummyRole end --执行操作逻辑 function BattleLogic.ExecuteOption(option) local opType = option[2] local opArg = option[3] if opType == 1 then --全局自动手动 for i=1, objList.size do local tmpObj = objList.vList[i] if tmpObj.camp == 0 then tmpObj.Auto = opArg == 1 end end elseif opType == 2 then --释放skill local role = objList.kvList[opArg] if role and role.skill then skillManualQueue:Enqueue(role.skill) end elseif opType == 3 then --释放superSkill local role = objList.kvList[opArg] if role and role.superSkill then skillManualQueue:Enqueue(role.superSkill) end elseif opType == 4 then --释放teamSkill BattleLogic.CastTeamSkill(0) elseif opType == 5 then --设置teamSkill自动手动 isAuto = opArg == 1 elseif opType == 6 then --切换单个角色自动手动 arg == uid * 10 + auto(0手动,1自动) local auto = opArg % 10 local uid = floor(opArg / 10) if objList.kvList[uid] then objList.kvList[uid].Auto = auto == 1 end end end function BattleLogic.HasObj(obj) return obj and objList.kvList[obj.uid] end function BattleLogic.CurFrame() return curFrame end function BattleLogic.CurStage() return stage end function BattleLogic.CurStageTime() local time = 0 if stage == 1 then time = stageFrame1 - curFrame elseif stage == 2 then time = stageFrame2 - curFrame end return time end function BattleLogic.Query(func, inCludeDeadRole) local list = {} local index = 1 if func then for i=1, objList.size do local v = objList.vList[i] 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 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 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 > stageFrame1 and stage == 1 then stage = 2 BattleLogic.Event:DispatchEvent(BattleEventName.BattleStageChange, stage) end if curFrame > stageFrame2 and stage == 2 then stage = 3 BattleLogic.Event:DispatchEvent(BattleEventName.BattleStageChange, stage) end if curFrame > teamSkillCastTime[teamSkillCastIndex] then if playerTeamSkillIndex == teamSkillCastIndex and playerSkillUsable then if playerTeamSkillList[teamSkillCastIndex] then playerTeamSkillList[teamSkillCastIndex]:Cast() playerTeamSkillIndex = playerTeamSkillIndex + 1 end end if enemyTeamSkillIndex == teamSkillCastIndex and enemySkillUsable then if enemyTeamSkillList[teamSkillCastIndex] then enemyTeamSkillList[teamSkillCastIndex]:Cast() enemyTeamSkillIndex = enemyTeamSkillIndex + 1 end end teamSkillCastIndex = min(teamSkillCastIndex + 1, #teamSkillCastTime) end if curFrame > maxFrame then BattleLogic.BattleEnd(0) return end for i=1, #optionRecord do if optionRecord[i][1] == curFrame then BattleLogic.ExecuteOption(optionRecord[i]) end end if playerSkillUsable and skillManualQueue.size > 0 then --手动操作的技能进入队列,等待释放 skillManualQueue:Dequeue():Cast() 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 --for i=1, #playerTeamSkillList do -- playerTeamSkillList[i].sp = min(playerTeamSkillList[i].sp + 1, playerTeamSkillList[i].spPass) --end -- --for i=1, #enemyTeamSkillList do -- enemyTeamSkillList[i].sp = min(enemyTeamSkillList[i].sp + 1, enemyTeamSkillList[i].spPass) --end -- --if playerMP == 100 and playerSkillUsable and isAuto then -- local teamSkill = playerTeamSkillList[playerTeamSkillIndex] -- if teamSkill.sp >= teamSkill.spPass then -- BattleLogic.CastTeamSkill(0) -- end --end -- --if enemyMP == 100 and enemySkillUsable then -- local teamSkill = enemyTeamSkillList[enemyTeamSkillIndex] -- if teamSkill.sp >= teamSkill.spPass then -- BattleLogic.CastTeamSkill(1) -- end --end BattleLogic.BuffMgr:Update() local bMyAllDead = true local bEnemyAllDead = true for i=1, objList.size do local tmpObj = objList.vList[i] if not tmpObj.isDead then tmpObj:Update() if tmpObj.camp == 0 then bMyAllDead = false else bEnemyAllDead = false end end end if bMyAllDead then BattleLogic.BattleEnd(0) 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 end local posDic = {3,2,4,1,5} --对位规则: 1敌方相同对位 2若死亡或不存在,选取相邻阵位最近且阵位索引最小的 function BattleLogic.GetAggro(camp, position) local minNeighbor = 100 local index = 100 local target local enemyCamp = camp == 0 and 1 or 0 for i=1, objList.size do if objList.vList[i].camp == enemyCamp and not objList.vList[i].isDead then if position == objList.vList[i].position then return objList.vList[i] else local neighbor = math.abs(posDic[position] - posDic[objList.vList[i].position]) if neighbor < minNeighbor then minNeighbor = neighbor index = objList.vList[i].position target = objList.vList[i] elseif neighbor == minNeighbor and objList.vList[i].position < index then minNeighbor = neighbor index = objList.vList[i].position target = objList.vList[i] end end end end return target end function BattleLogic.ResetTeamSkillCD(camp) local skill = camp == 0 and playerTeamDummyRole.curSkill or enemyTeamDummyRole.curSkill if skill then skill.spPass = floor(skill.cd % 100 * BattleLogic.GameFrameRate) skill.sp = skill.spPass end end function BattleLogic.CastTeamSkill(camp) if camp == 0 then local teamSkill = playerTeamSkillList[playerTeamSkillIndex] if teamSkill then teamSkill:Cast() if playerTeamSkillIndex == #playerTeamSkillList then playerTeamSkillIndex = 1 else playerTeamSkillIndex = playerTeamSkillIndex + 1 end playerMP = 0 end else local teamSkill = enemyTeamSkillList[enemyTeamSkillIndex] if teamSkill then teamSkill:Cast() if enemyTeamSkillIndex == #enemyTeamSkillList then enemyTeamSkillIndex = 1 else enemyTeamSkillIndex = enemyTeamSkillIndex + 1 end enemyMP = 0 end end end --Debug专用 function BattleLogic.SetDebug() for i=1, objList.size do local v = objList.vList[i] 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.RecordDamage(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, damageArgs:%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