miduo_server/luafight/Modules/Battle/Logic/BattleLogic.lua

767 lines
22 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.

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