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

693 lines
20 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
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,3 do
if playerTeamSkillList[i] then
skillPool:Put(playerTeamSkillList[i])
playerTeamSkillList[i]=nil
end
end
for i=1, #fightData.playerData.teamSkill do
local skill = skillPool:Get()
skill:Init(playerTeamDummyRole, fightData.playerData.teamSkill[i], 0)
playerTeamSkillList[i] = skill
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
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, #fightData.enemyData[BattleLogic.CurOrder].teamSkill do
local skill = skillPool:Get()
skill:Init(enemyTeamDummyRole, fightData.enemyData[BattleLogic.CurOrder].teamSkill[i], 0)
enemyTeamSkillList[i] = skill
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
BattleLogic.TakeTeamPassivity(enemyTeamDummyRole, id, 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
local skill = skillPool:Get()
skill:Init(enemyTeamDummyRole, fightData.enemyData[BattleLogic.CurOrder].teamSkill[i], 0)
enemyTeamSkillList[i] = skill
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
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)
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.HasObj(obj)
return obj and objList:Get(obj.uid)
end
function BattleLogic.CurFrame()
return curFrame
end
function BattleLogic.Query(func, inCludeDeadRole)
local list = {}
local index = 1
if func then
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
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 > 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
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 minNeighbor = 100
local index = 100
local target
local enemyCamp = role.camp == 0 and 1 or 0
objList:Foreach(function(k, v)
if v.camp == enemyCamp and not v.isDead then
if role.position == v.position then
minNeighbor = 0
index = v.position
target = v
return "break" --终止foreach
else
local neighbor = math.abs(role.position - v.position)
if neighbor < minNeighbor then
minNeighbor = neighbor
index = v.position
target = v
elseif neighbor == minNeighbor and v.position < index then
minNeighbor = neighbor
index = v.position
target = v
end
end
end
end)
return target
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 and math.abs(target.position - list[i].position) <= 1 then
table.insert(posList, list[i])
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