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

577 lines
18 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 curUid
local curBuffId
local curFrame
local playerSkillUsable
local enemySkillUsable
BattleLogic.Type = 0 --1 故事副本 2 地图探索 3 竞技场 4 秘境boss 5 解锁秘境 6 公会战 7 血战 8 兽潮
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 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 = 15 * BattleLogic.GameFrameRate --前期转中期的时间点
local stageFrame2 = 30 * BattleLogic.GameFrameRate --中期转后期的时间点
local curStageFrame
local teamSkillCastTime = {7 * BattleLogic.GameFrameRate,
22 * BattleLogic.GameFrameRate,
45 * 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()
curUid = 0
curBuffId = 0
curFrame = 0
stage = 0
playerTeamDummyRole.isDebug = false
playerTeamDummyRole.Event:ClearEvent()
enemyTeamDummyRole.isDebug = false
enemyTeamDummyRole.Event:ClearEvent()
playerSkillUsable = true
enemySkillUsable = true
BattleLogic.Event:ClearEvent()
BattleLogic.BuffMgr:Init()
BattleLogic.IsEnd = false
BattleLogic.Result = -1
end
function BattleLogic.StartOrder()
BattleLogic.CurOrder = BattleLogic.CurOrder + 1
stage = 0
curStageFrame = 0
teamSkillCastIndex = 1
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,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[skill.cd] = 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
BattleUtil.Passivity[id](playerTeamDummyRole, 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[skill.cd] = 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
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
local skill = skillPool:Get()
skill:Init(enemyTeamDummyRole, fightData.enemyData[BattleLogic.CurOrder].teamSkill[i], 0)
enemyTeamSkillList[skill.cd] = 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
BattleUtil.Passivity[id](enemyTeamDummyRole, args)
end
end
end
end
function BattleLogic.GetTeamSkill(camp, pos)
return camp == 0 and playerTeamSkillList[pos] or enemyTeamSkillList[pos]
end
function BattleLogic.GetTeamSkillCastSlider()
if playerTeamDummyRole.isDebug or teamSkillCastIndex > #teamSkillCastTime then
return 0
end
local slider = (teamSkillCastTime[teamSkillCastIndex] - curStageFrame)
if teamSkillCastIndex == 1 then
slider = slider / teamSkillCastTime[teamSkillCastIndex]
elseif teamSkillCastIndex == 2 then
slider = slider / (teamSkillCastTime[teamSkillCastIndex] - stageFrame1)
elseif teamSkillCastIndex == 3 then
slider = slider / (teamSkillCastTime[teamSkillCastIndex] - stageFrame2)
end
return slider
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.GetTeamSkillCaster(camp)
return camp == 0 and playerTeamDummyRole or enemyTeamDummyRole
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.CurStageSlider()
local slider = 0
if stage == 1 then
slider = (stageFrame1 - curStageFrame) / stageFrame1
elseif stage == 2 then
slider = (stageFrame2 - curStageFrame) / (stageFrame2 - stageFrame1)
elseif stage == 3 then
slider = (maxFrame / BattleLogic.TotalOrder - curStageFrame) / (maxFrame / BattleLogic.TotalOrder - stageFrame2)
end
return slider
end
--表现层调用,显示每个阶段剩余时间
function BattleLogic.CurStageTime()
local time = 0
if stage == 1 then
time = (stageFrame1 - curStageFrame) / BattleLogic.GameFrameRate
elseif stage == 2 then
time = (stageFrame2 - curStageFrame) / BattleLogic.GameFrameRate
elseif stage == 3 then
time = (maxFrame / BattleLogic.TotalOrder - curStageFrame) / BattleLogic.GameFrameRate
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 > maxFrame then
BattleLogic.BattleEnd(0)
return
end
curStageFrame = curStageFrame + 1
if curStageFrame > 0 and stage == 0 then
stage = 1
BattleLogic.Event:DispatchEvent(BattleEventName.BattleStageChange, stage)
end
if curStageFrame > stageFrame1 and stage == 1 then
stage = 2
BattleLogic.Event:DispatchEvent(BattleEventName.BattleStageChange, stage)
end
if curStageFrame > stageFrame2 and stage == 2 then
stage = 3
BattleLogic.Event:DispatchEvent(BattleEventName.BattleStageChange, stage)
end
if teamSkillCastIndex <= #teamSkillCastTime and curStageFrame > teamSkillCastTime[teamSkillCastIndex] then
if not playerTeamDummyRole.isDebug and playerTeamSkillList[teamSkillCastIndex] then
playerTeamSkillList[teamSkillCastIndex]:Cast()
end
if not enemyTeamDummyRole.isDebug and enemyTeamSkillList[teamSkillCastIndex] then
enemyTeamSkillList[teamSkillCastIndex]:Cast()
end
teamSkillCastIndex = teamSkillCastIndex + 1
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()
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)
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
end
local posDic = {3,2,4,1,5}
--对位规则: 1敌方相同对位 2若死亡或不存在选取相邻阵位最近且阵位索引最小的
function BattleLogic.GetAggro(role)
local minNeighbor = 100
local index = 100
local target
local enemyCamp = role.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 role.position == objList.vList[i].position then
return objList.vList[i]
else
local neighbor = math.abs(posDic[role.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
--获取对位相邻站位的人 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(posDic[target.position] - posDic[list[i].position]) <= 1 then
table.insert(posList, list[i])
end
end
end
return posList
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[teamSkillCastIndex]
if teamSkill then
teamSkill:Cast()
end
else
local teamSkill = enemyTeamSkillList[teamSkillCastIndex]
if teamSkill then
teamSkill:Cast()
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