From 649b36b642546062ab5102b6225b9f78ea72309d Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期二, 04 十一月 2025 18:11:02 +0800
Subject: [PATCH] 129 【战斗】战斗系统-服务端(优化完整战报仅包含战斗相关封包,结算奖励相关如物品,经验,货币,挑战次数等统一放在战报数据B430后同步)
---
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py | 1314 +++++++++++++++++++++++++++++++++--------------------------
1 files changed, 732 insertions(+), 582 deletions(-)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
index dab5601..398e8b0 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -21,30 +21,32 @@
import ChConfig
import PlayerTask
+import PlayerActivity
+import PlayerViewCache
import ChPyNetSendPack
import NetPackCommon
import PlayerControl
import GameWorld
-import FBCommon
import IpyGameDataPY
import PlayerOnline
import NPCCommon
import ShareDefine
import PyGameData
-import ItemControler
import SkillCommon
import BattleObj
import TurnPassive
import TurnSkill
import TurnBuff
+import FBCommon
+import CommFunc
import ObjPool
+import FBLogic
import random
import time
import json
-TimelineSet = 10000 # 单回合最大时间轴
-PosNumMax = 10 # 最大站位编号
+PosNumMax = 7 # 最大站位编号
ActionNumStart = -1 # 起始行动位置编号,一般是从1开始,如果有加主公、红颜等则扣除相应位置值,如从0或-1开始
# 回合战斗流程状态
@@ -55,7 +57,8 @@
FightState_FightEnd, # 3 战斗结束
FightState_Award, # 4 结算奖励
FightState_Over, # 5 结束状态,无特殊意义,仅代表所有处理结束了,与Start对应
-) = range(6)
+FightState_Rest, # 6 结束并休息,一般是前端主动退出并休息的
+) = range(7)
class BatLineup():
## 战斗阵容
@@ -71,6 +74,11 @@
self.lingshouObjIDDict = {} # 灵兽战斗单位 {位置编号:batObjID, ...}
self.beautyObjIDDict = {} # 红颜战斗单位 {位置编号:batObjID, ...}
self.actionNum = ActionNumStart # 行动位置,从1开始
+ self.totalHurt = 0 # 阵容总输出
+
+ #特殊
+ self.bossID = 0
+ self.bossPosView = 0
return
def getPlayerID(self): return self.turnFight.playerID # 发起的玩家ID
@@ -84,6 +92,8 @@
self.ownerID = lineupInfo.get("PlayerID", 0) # 阵容所属的玩家ID
self.shapeType = lineupInfo.get("ShapeType", 0)
self.fightPower = lineupInfo.get("FightPower", 0)
+ self.bossID = lineupInfo.get("BossID", 0)
+ self.bossPosView = lineupInfo.get("BossPosView", 0)
SummonLineupObjs(self, self.faction, self.num, lineupInfo, self.getPlayerID())
return
@@ -100,7 +110,21 @@
self.lingshouObjIDDict = {}
self.beautyObjIDDict = {}
self.fightPower = 0
+ self.totalHurt = 0
return
+
+ def getDeadObjCnt(self):
+ ## 获取本阵容目前死亡队员数
+ deadCnt = 0
+ batObjMgr = BattleObj.GetBatObjMgr()
+ for objID in self.posObjIDDict.values():
+ batObj = batObjMgr.getBatObj(objID)
+ if not batObj:
+ continue
+ if batObj.IsAlive():
+ continue
+ deadCnt += 1
+ return deadCnt
class BatFaction():
## 战斗阵营
@@ -109,6 +133,7 @@
self.turnFight = turnFight # TurnFight
self.faction = faction
self.lineupDict = {} # 该阵营所有阵容信息 {编号:BatLineup, ...}
+ self.totalHurt = 0 # 阵营总输出
return
def getBatlineup(self, num=1):
@@ -120,6 +145,8 @@
lineup = BatLineup(self.faction, num, self.turnFight)
self.lineupDict[num] = lineup
return lineup
+
+ def getTotalHurt(self): return self.totalHurt # 阵营总输出
def clearLineups(self):
## 清除所有战斗阵容
@@ -147,45 +174,92 @@
self.state = -1 # -1 代表未战斗
self.turnNum = 1 # 当前第x回合,默认第1回合开始
self.turnMax = 15 # 最大回合数
+ self.turnNumStart = 0 # 已处理第x回合开始
self.enterLogic = False # 是否已执行进场逻辑
- self.turnStart = 0 # 已执行回合开始值,如第1回合开始已执行则为1,第2回合为2
- self.turnEnd = 0 # 已执行回合结束值,如第1回合结束已执行则为1,第2回合为2
self.winFaction = 0 # 本场战斗结束标记,获胜阵营,为0时代表未结束,所有小队打完或失败才有结果,0-未结束,>0-获胜的阵营
+ self.isWin = False
self.batBuffer = "" # 战报buffer,战报暂时只保留最后一个小队的
self.isNeedReport = isNeedReport # 是否需要战报
self.msgDict = {} # 扩展信息字典,一般由MapID绑定的功能决定信息内容 {k:v, ...}
+ self._kvDict = {} # 自定义信息字典,不会被重置 {k:v, ...}
+ self.awardData = None # 战斗奖励设置的数据,可以是任意数据格式,由功能自行决定,会传递给 OnTurnFightAward 处理
self.factionDict = {} # 战斗阵营 {faction:BatFaction, ...},一般是只有两个阵营,faction为1或2,每个阵营支持多个阵容
self.actionSortList = [] # 阵容行动顺序 [[faction, num], ...]
self.actionIndex = 0 # 行动顺序索引
- self.timeline = 0 # 时间轴节点 turnNum*1000+actionIndex*100++actionNum
-
self.startTime = 0 # 开始时间戳,支持毫秒小数
self.costTime = 0 # 单场战斗总耗时,支持毫秒小数
+ self._oneActionUseSkillCntDict = {} # 某对象行动开始后所有对象累计使用技能次数,用于单对象单次行动中限制每个对象的最高触发技能次数 {objID:useCnt, ...}
+
+ # pve 多小队 - 一般只有PVE用到
+ self.lineupIndex = 0 # 当前小队索引
+ self.lineupIDList = [] # npc小队列表
+ self.strongerLV = 0 # npc成长等级
+ self.difficulty = 0 # npc难度
+
+ # pvp 目标
+ self.tagPlayerID = 0
+ self.tagViewCache = None
return
- def setTurn(self, mapID, funcLineID, turnMax, isNeedReport=False, msgDict={}):
+ def setTurnFight(self, mapID, funcLineID, turnMax, isNeedReport=False, msgDict={}):
## 设置本场回合战斗设定
self.mapID = mapID
self.funcLineID = funcLineID
self.turnMax = turnMax # 最大回合数
self.isNeedReport = isNeedReport
+ self.setPVE()
+ self.setPVP()
self.msgDict = {}
- self.resetTurn(msgDict)
+ self._kvDict = {}
+ self.awardData = None
+ self.nextTurnFight(msgDict)
return
- def resetTurn(self, msgDict):
+ def setPVE(self, lineupIDList=[], strongerLV=0, difficulty=0):
+ self.lineupIndex = 0
+ self.lineupIDList = lineupIDList
+ self.strongerLV = strongerLV
+ self.difficulty = difficulty
+ return
+
+ def setPVP(self, tagPlayerID=0, tagViewCache=None):
+ self.tagPlayerID = tagPlayerID
+ self.tagViewCache = tagViewCache
+ return
+
+ def isFBMap(self):
+ ## 是否副本地图中,非主线的均视为副本
+ return self.mapID not in [ChConfig.Def_FBMapID_Main, ChConfig.Def_FBMapID_MainBoss]
+
+ def GetDictByKey(self, key): return self._kvDict.get(key, 0)
+ def SetDict(self, key, value): self._kvDict[key] = value
+
+ #def setPVPTeam(self):
+ # return
+
+ def nextTurnFight(self, msgDict={}):
## 一般用于玩家发起的战斗,在需要保留玩家阵容属性及状态的情况下,重置回合进入下一场战斗
self.turnNum = 1
+ self.turnNumStart = 0
self.enterLogic = False
- self.turnStart = 0
- self.turnEnd = 0
self.winFaction = 0
- self.batBuffer = "" # 战报buffer
+ self.isWin = False
self.msgDict.update(msgDict)
self.startTime = time.time()
self.costTime = 0
+ ResetByNextTeam(self)
return
+
+ def haveNextLineup(self):
+ ## 是否可以打下一小队,获胜且还有下一小队时可打
+ return (self.winFaction == ChConfig.Def_FactionA and self.lineupIndex < len(self.lineupIDList) - 1)
+ def nextLineupID(self):
+ ## 下一小队ID
+ if not self.haveNextLineup():
+ return 0
+ self.lineupIndex += 1
+ return self.lineupIDList[self.lineupIndex]
def setFactionLineup(self, faction, lineupDict):
## 设置阵营阵容
@@ -218,22 +292,6 @@
GameWorld.DebugLog("阵容战力排序[isPlayer, fp, sortV, f, n]: %s" % sortList)
GameWorld.DebugLog("阵容行动顺序[f, n]: %s" % self.actionSortList)
- return
-
- def getTimeline(self): return self.timeline
- def setTimeline(self, turnNum):
- '''回合战斗的时间轴节点 ,即第几回合开始,每个回合支持9999个行动节点
- @param turnNum: 第x回合
- '''
- self.timeline = turnNum * TimelineSet + 0
- GameWorld.DebugLog("时间节点更新: %s" % self.timeline)
- OnTimelineChange(self)
- return
- def addTimeline(self):
- ## 每切换一个行动单位可视为一个行动节点,即代表单回合战斗中的某一个时间节点
- self.timeline += 1
- GameWorld.DebugLog("时间节点更新: %s" % self.timeline)
- OnTimelineChange(self)
return
def getBatFaction(self, faction=ChConfig.Def_FactionA):
@@ -277,9 +335,9 @@
return 0
- def exitFight(self):
+ def exitFight(self, rest=False):
## 退出战斗
- self.syncState(FightState_Over)
+ self.syncState(FightState_Over if not rest else FightState_Rest)
for batFaction in self.factionDict.values():
batFaction.clearLineups()
self.state = -1
@@ -288,7 +346,8 @@
def startFight(self):
## 准备就绪,开始战斗
self.state = FightState_Start
- self.setTimeline(1)
+ self.turnNum = 1
+ self.turnNumStart = 0
self.syncInit()
return
@@ -333,7 +392,10 @@
tfObj.MaxHP = batObj.GetMaxHP() % ChConfig.Def_PerPointValue
tfObj.MaxHPEx = batObj.GetMaxHP() / ChConfig.Def_PerPointValue
tfObj.LV = batObj.GetLV()
- tfObj.PosNum = posNum
+ if batLineup.bossPosView and batLineup.bossID == batObj.GetNPCID():
+ tfObj.PosNum = batLineup.bossPosView
+ else:
+ tfObj.PosNum = posNum
tfObj.AngreXP = batObj.GetXP()
tfLineup.ObjList.append(tfObj)
tfLineup.ObjCnt = len(tfLineup.ObjList)
@@ -342,6 +404,11 @@
clientPack.FactionList.append(tfFaction)
clientPack.FactionCnt = len(clientPack.FactionList)
self.addBatPack(clientPack)
+ return
+
+ def syncHelp(self, msgDict):
+ ## 通知帮助信息,一般是副本用
+ self.syncState(self.state, msgDict)
return
def syncState(self, state, msgDict={}):
@@ -374,25 +441,40 @@
headStr = "%02x%02x" % (clientPack.Head.Cmd, clientPack.Head.SubCmd)
else:
headStr = "%02x%02x" % (clientPack.Cmd, clientPack.SubCmd)
- GameWorld.DebugLog("回合战斗过程封包: %s, isNeedReport=%s,%s" % (headStr, self.isNeedReport, self.guid))
if self.isNeedReport:
- self.batBuffer += clientPack.GetBuffer()
- # 有玩家的统一每个包单独发送,同样也支持战报统计
- if self.curPlayer:
- NetPackCommon.SendFakePack(self.curPlayer, clientPack)
- else:
+ packBuff = clientPack.GetBuffer()
+ buffLen = len(packBuff)
+ GameWorld.DebugLog("回合战斗过程封包: %s, len:%s" % (headStr, buffLen))
+ self.batBuffer += CommFunc.WriteWORD("", buffLen)
+ self.batBuffer += packBuff
ObjPool.GetPoolMgr().release(clientPack)
+ else:
+ GameWorld.DebugLog("回合战斗过程封包: %s" % (headStr))
+ # 有玩家的统一每个包单独发送,同样也支持战报统计
+ if self.curPlayer:
+ NetPackCommon.SendFakePack(self.curPlayer, clientPack)
+ else:
+ ObjPool.GetPoolMgr().release(clientPack)
return
+
+ def ResetOneActionUseSkillCnt(self): self._oneActionUseSkillCntDict = {}
+ def GetOneActionUseSkillCnt(self, objID): return self._oneActionUseSkillCntDict.get(objID, 0)
+ def SetOneActionUseSkillCnt(self, objID, useCnt):
+ self._oneActionUseSkillCntDict[objID] = useCnt
+ return useCnt
class TurnFightMgr():
## 回合战斗管理器
def __init__(self):
+ self.lastRequestTick = 0
self.turnFightDict = {} # {guid:TurnFight, ...}
return
- def addTurnFight(self, mapID, funcLineID=0, playerID=0):
- tf = TurnFight(mapID, funcLineID, playerID, False)
+ def addTurnFight(self, mapID, funcLineID=0, playerID=0, isNeedReport=False):
+ tf = ObjPool.GetPoolMgr().acquire(TurnFight, mapID, funcLineID, playerID, isNeedReport)
+ if not tf:
+ tf = TurnFight(mapID, funcLineID, playerID, isNeedReport) # 一般是不可能,为了点出代码
self.turnFightDict[tf.guid] = tf
return tf
@@ -402,6 +484,7 @@
return
turnFight.exitFight()
self.turnFightDict.pop(guid, None)
+ ObjPool.GetPoolMgr().release(turnFight)
return
def getTurnFight(self, guid):
@@ -430,12 +513,6 @@
self.levelNum = 0 # 关卡编号
self.waveMax = 6 # 本关最大波数,每波有多个小队,每个小队即为一张战斗 TurnFight
self.wave = 0 # 当前刷怪波,注意不是玩家当前进度波,比如被击杀会回退一波
- self.teamNum = 1 # 当前小队
- self.teamMax = 1 # 当前波最大小队,某场战斗可能包含多个小队,所有小队混流击杀完才算过了本波
- self.nextTeam = False # 下次前端请求战斗是否是下一小队,否则都是重新刷新当前进度怪
- self.waveLineupList = [] # 小队列表
- self.strongerLV = 0
- self.difficulty = 0
self.turnFight = GetTurnFightMgr().addTurnFight(ChConfig.Def_FBMapID_Main, 0, playerID)
return
@@ -458,10 +535,30 @@
% (chapterID, levelNum, nowChapterID, fixNowValue), curPlayer.GetPlayerID())
return
-def GetPlayerLineupInfoByCache(playerID, lineupID):
- ## 获取玩家阵容信息 - 根据玩家查看缓存
- lineupInfo = {}
+
+def GetCacheLineupFightPower(tagViewCache, lineupID):
+ lineupInfo = GetCacheLineupInfo(tagViewCache, lineupID)
+ return lineupInfo.get("FightPower", 0)
+def GetCacheLineupInfo(tagViewCache, lineupID):
+ ## 根据查看缓存获取阵容信息,一般是 GetPlayerLineupInfo 返回的结果
+ plusDict = tagViewCache.GetPlusDict()
+ lineupDict = plusDict.get("Lineup", {})
+ lineupInfo = lineupDict.get("%s" % lineupID, {})
+ if not lineupInfo:
+ lineupInfo = lineupDict.get("%s" % ShareDefine.Lineup_Main, {})
return lineupInfo
+
+def GetPlayerLineupFightPower(curPlayer, lineupID):
+ ## 获取玩家阵容战力,一般用于直接获取阵容战力记录用
+ return GetPlayerLineup(curPlayer, lineupID).fightPower
+def GetPlayerLineup(curPlayer, lineupID):
+ ## 获取玩家阵容
+ olPlayer = PlayerOnline.GetOnlinePlayer(curPlayer)
+ lineup = olPlayer.GetLineup(lineupID)
+ if lineup.IsEmpty():
+ GameWorld.DebugLog("玩家没有目标阵容默认取主阵容! lineupID=%s" % lineupID)
+ lineup = olPlayer.GetLineup(ShareDefine.Lineup_Main)
+ return lineup
def GetPlayerLineupInfo(curPlayer, lineupID):
## 获取玩家阵容信息,可用于战斗或查看缓存,因为可能取玩家的缓存进行对战,所以统一使用json格式,前端通用
@@ -469,12 +566,13 @@
# @return: 阵容全部信息json字典,前端通用格式
playerID = curPlayer.GetPlayerID()
- lineup = PlayerOnline.GetOnlinePlayer(curPlayer).GetLineup(lineupID)
+ lineup = GetPlayerLineup(curPlayer, lineupID)
+ if lineup.IsEmpty():
+ return {}
- lineupInfo = {"PlayerID":playerID, "FightPower":lineup.fightPower, "ShapeType":lineup.shapeType}
heroDict = {}
curPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptHero)
- for posNum in lineup.lineupHeroDict.keys():
+ for posNum in lineup.GetPosNumList():
hero = lineup.GetLineupHero(posNum)
heroID = hero.heroID
itemIndex = hero.itemIndex
@@ -497,8 +595,11 @@
"AttrDict":{str(k):v for k, v in hero.heroBatAttrDict.items() if v > 0},
"SkillIDList":skillIDlist,
}
- lineupInfo.update({"Hero":heroDict})
+
+ if not heroDict:
+ return {}
+ lineupInfo = {"PlayerID":playerID, "FightPower":lineup.fightPower, "ShapeType":lineup.shapeType, "Hero":heroDict}
return lineupInfo
def GetNPCLineupInfo(lineupID, strongerLV=0, difficulty=0):
@@ -510,23 +611,25 @@
ipyData = IpyGameDataPY.GetIpyGameData("NPCLineup", lineupID)
if not ipyData:
return {}
+ bossID = ipyData.GetBossID()
+ bossPosView = ipyData.GetBossPosView()
heroDict = {}
- for posNum in range(1, 1 + 10):
+ for posNum in range(1, 1 + 6):
if not hasattr(ipyData, "GetPosNPCID%s" % posNum):
break
npcID = getattr(ipyData, "GetPosNPCID%s" % posNum)()
if not npcID:
continue
- battleDict = GetNPCBattleDict(npcID, strongerLV, difficulty)
+ battleDict = GetNPCBattleDict(ipyData, npcID, strongerLV, difficulty)
if not battleDict:
continue
heroDict[str(posNum)] = battleDict
- lineupInfo = {"NPCLineupID":lineupID, "Hero":heroDict}
+ lineupInfo = {"NPCLineupID":lineupID, "Hero":heroDict, "BossID":bossID, "BossPosView":bossPosView}
return lineupInfo
-def GetNPCBattleDict(npcID, strongerLV=0, difficulty=0):
+def GetNPCBattleDict(lineupIpyData, npcID, strongerLV=0, difficulty=0):
## 获取NPC战斗相关字典,支持成长NPC
# @param strongerLV: 成长等级
# @param difficulty: 难度系数
@@ -553,8 +656,21 @@
else:
heroID = 0
skinID = 0
- skillIDList = [] + npcData.GetSkillIDList()
+ skillIDList = []# + npcData.GetSkillIDList()
+ # boss额外随机技能
+ bossID = lineupIpyData.GetBossID()
+ if npcID == bossID:
+ skillIDExList = lineupIpyData.GetSkillIDExList()
+ if skillIDExList:
+ randSkillIDExList = [] + list(skillIDExList)
+ skillExCnt = lineupIpyData.GetSkillExCnt()
+ if skillExCnt > 0 and len(randSkillIDExList) > skillExCnt:
+ random.shuffle(randSkillIDExList)
+ randSkillIDExList = randSkillIDExList[:skillExCnt]
+ skillIDList += randSkillIDExList
+ GameWorld.DebugLog("阵容boss技能: %s, 随机附加技能: %s" % (skillIDList, randSkillIDExList))
+
# 成长怪属性
batAttrDict = GetNPCStrongerAttrDict(npcID, lvIpyData, npcStronger, difficulty)
if not batAttrDict:
@@ -567,7 +683,10 @@
ChConfig.AttrID_ParryRate:npcData.GetParryRate(), ChConfig.AttrID_ParryRateDef:npcData.GetParryRateDef(),
ChConfig.AttrID_SuckHPPer:npcData.GetSuckHPPer(), ChConfig.AttrID_SuckHPPerDef:npcData.GetSuckHPPerDef(),
}
- batAttrDict.update(npcData.GetSpecAttrInfo())
+ exAttrDict = npcData.GetSpecAttrInfo()
+ for attrIDStr, attrValue in exAttrDict.items():
+ attrID = int(attrIDStr)
+ batAttrDict[attrID] = batAttrDict.get(attrID, 0) + attrValue
battleDict = {"NPCID":npcID,
"HeroID":heroID,
@@ -586,7 +705,7 @@
angerSkillID = heroIpyData.GetAngerSkillID()
skillIDList = [normalSkillID, angerSkillID]
- breakIpyDataList = IpyGameDataPY.GetIpyGameDataList("HeroBreak", heroID)
+ breakIpyDataList = IpyGameDataPY.GetIpyGameDataListNotLog("HeroBreak", heroID)
if breakIpyDataList:
for breakIpyData in breakIpyDataList:
if breakIpyData.GetBreakLV() > breakLV:
@@ -595,7 +714,7 @@
if skillID:
skillIDList.append(skillID)
- awakeIpyDataList = IpyGameDataPY.GetIpyGameDataList("HeroAwake", heroID)
+ awakeIpyDataList = IpyGameDataPY.GetIpyGameDataListNotLog("HeroAwake", heroID)
if awakeIpyDataList:
for awakeIpyData in awakeIpyDataList:
if awakeIpyData.GetAwakeLV() > awakeLV:
@@ -644,17 +763,16 @@
if not curPlayer:
return
- tfGUID = batLineup.turnFight.guid
+ turnFight = batLineup.turnFight
+ tfGUID = turnFight.guid
lineupPlayerID = lineupInfo.get("PlayerID", 0) # 阵容所属玩家ID
heroDict = lineupInfo.get("Hero", {})
batObjMgr = BattleObj.GetBatObjMgr()
initXP = IpyGameDataPY.GetFuncCfg("AngerXP", 1)
- atkBackSkillIDList = IpyGameDataPY.GetFuncEvalCfg("ParryCfg", 2)
for posNumKey, heroInfo in heroDict.items():
posNum = int(posNumKey)
- atkBackSkillID = 0 # 反击技能ID
fightPower = 0
skillIDList = [] # 战斗对象可能改变属性或技能,重新创建,防止误修改来源值
attrDict = {}
@@ -664,12 +782,15 @@
heroID = heroInfo.get("HeroID", 0)
skinID = heroInfo.get("SkinID", 0)
lv = heroInfo.get("LV", 1)
+ specialty, atkDistType, country, sex, job = 0, 1, 0, 1, 0
heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID) if heroID else None
if heroIpyData:
- atkDistType = heroIpyData.GetAtkDistType()
objName = heroIpyData.GetName()
+ specialty = heroIpyData.GetSpecialty()
+ atkDistType = heroIpyData.GetAtkDistType()
country = heroIpyData.GetCountry()
sex = heroIpyData.GetSex()
+ job = heroIpyData.GetJob()
if lineupPlayerID:
fightPower = heroInfo.get("FightPower", 0)
@@ -681,10 +802,7 @@
if not npcDataEx:
continue
if not heroIpyData:
- atkDistType = npcDataEx.GetAtkDistType()
objName = npcDataEx.GetNPCName()
- country = npcDataEx.GetCountry()
- sex = npcDataEx.GetSex()
batObj = batObjMgr.addBatObj()
if not batObj:
@@ -701,33 +819,256 @@
batObj.SetFightPower(fightPower)
batObj.SetLV(lv)
batObj.SetAtkDistType(atkDistType)
+ batObj.SetSpecialty(specialty)
batObj.SetCountry(country)
batObj.SetSex(sex)
+ batObj.SetJob(job)
batObj.SetHero(heroID, skinID)
- if atkDistType == ChConfig.AtkDistType_Short:
- atkBackSkillID = atkBackSkillIDList[0] if len(atkBackSkillIDList) > 0 else 0
- elif atkDistType == ChConfig.AtkDistType_Long:
- atkBackSkillID = atkBackSkillIDList[1] if len(atkBackSkillIDList) > 1 else 0
- if atkBackSkillID:
- skillIDList.append(atkBackSkillID)
skillManager = batObj.GetSkillManager()
skillManager.SkillReset()
for skillID in skillIDList:
skillManager.LearnSkillByID(skillID)
batLineup.posObjIDDict[posNum] = objID
- GameWorld.DebugLog("AddBatObj %s,skill=%s" % (GetObjName(batObj), skillIDList))
+ GameWorld.DebugLog("AddBatObj %s,skill=%s" % (GetObjName(batObj), skillManager.GetSkillIDList()))
+ ResetObjSkill(batObj)
+
+ if npcID:
+ #副本指定NPC属性
+ fbNPCInitAttrDict = FBLogic.GetFBNPCInitAttr(curPlayer, turnFight, batObj)
+ if fbNPCInitAttrDict:
+ GameWorld.DebugLog("副本指定NPC初始化属性: npcID=%s, %s" % (npcID, fbNPCInitAttrDict))
+ attrDict = {str(k):v for k, v in fbNPCInitAttrDict.items()} # 统一格式
batObj.InitBatAttr({int(k):v for k, v in attrDict.items()}, initXP)
return
+
+def ResetByNextTeam(turnFight):
+ ## 切换下一小队时重置相关,目前设置仅保留血量、怒气、已被击杀的不复活,其他重置
+
+ batFaction = turnFight.getBatFaction(ChConfig.Def_FactionA)
+ if not batFaction:
+ return
+ GameWorld.DebugLog("切换小队重置玩家阵容武将...")
+ batLineup = batFaction.getBatlineup(1) # 只处理玩家阵容
+ batObjMgr = BattleObj.GetBatObjMgr()
+ for objID in batLineup.posObjIDDict.values():
+ batObj = batObjMgr.getBatObj(objID)
+ if not batObj:
+ continue
+ objName = GetObjName(batObj)
+ if not batObj.IsAlive():
+ GameWorld.DebugLog(" 已被击杀不处理! %s" % (objName))
+ continue
+ GameWorld.DebugLog("重置武将: %s, HP:%s/%s, XP:%s" % (objName, batObj.GetHP(), batObj.GetMaxHP(), batObj.GetXP()))
+
+ # 清除buff
+ buffMgr = batObj.GetBuffManager()
+ buffMgr.ClearBuff()
+
+ # 重置技能
+ ResetObjSkill(batObj)
+
+ # 重刷属性、被动
+ TurnBuff.RefreshBuffAttr(batObj)
+ TurnPassive.RefreshPassive(batObj)
+
+ return
+
+def CheckFightCD(curPlayer, tick, selfKey):
+ ## 是否战斗请求CD中
+
+ # 所有玩家公共CD,待扩展
+ tfMgr = GetTurnFightMgr()
+ pubCD = IpyGameDataPY.GetFuncCfg("TurnFightCD", 1)
+ if pubCD:
+ if tfMgr.lastRequestTick and tick - tfMgr.lastRequestTick <= pubCD:
+ GameWorld.DebugLog("回合制战斗请求服务器公共CD中!")
+ PlayerControl.NotifyCode(curPlayer, "BattleCoolDown")
+ return True
+
+ # 个人CD
+ selfCD = IpyGameDataPY.GetFuncCfg("TurnFightCD", 2)
+ lastTick = curPlayer.GetDictByKey(selfKey)
+ if selfCD and lastTick and tick - lastTick <= selfCD:
+ GameWorld.DebugLog("回合制战斗请求CD中: %s" % selfKey)
+ PlayerControl.NotifyCode(curPlayer, "BattleCoolDown")
+ return True
+
+ tfMgr.lastRequestTick = tick
+ curPlayer.SetDict(selfKey, tick)
+ return False
+
+#// B4 10 回合制战斗 #tagCMTurnFight
+#
+#struct tagCMTurnFight
+#{
+# tagHead Head;
+# DWORD MapID; // 自定义地图ID,可用于绑定战斗地图场景功能(如主线boss、爬塔、竞技场等)
+# DWORD FuncLineID; // MapID对应的扩展值,如具体某个关卡等
+# BYTE TagType; // 目标类型,0-NPC阵容,1-玩家
+# DWORD TagID; // 目标类型对应的ID,如玩家ID
+# BYTE ValueCount;
+# DWORD ValueList[ValueCount]; // 附加值列表,可选,具体含义由MapID决定
+#};
+def OnTurnFight(index, clientData, tick):
+ ''' 本战斗会一次性处理完所有小队战斗,以战报的形式下发,目前除了主线小怪分段战斗外,均使用该战斗
+ '''
+ curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+ mapID = clientData.MapID
+ funcLineID = clientData.FuncLineID
+ tagType = clientData.TagType
+ tagID = clientData.TagID
+ valueList = clientData.ValueList
+
+ GameWorld.DebugLog("----- 回合制战斗请求: mapID=%s,funcLineID=%s,tagType=%s,tagID=%s,valueList=%s"
+ % (mapID, funcLineID, tagType, tagID, valueList), curPlayer.GetPlayerID())
+
+ reqRet = FBLogic.OnTurnFightRequest(curPlayer, mapID, funcLineID, tagType, tagID, valueList)
+ if not reqRet:
+ return
+ funcLineID = reqRet[1] if len(reqRet) > 1 else funcLineID
+
+ fbIpyData = FBCommon.GetFBIpyData(mapID)
+ fbLineIpyData = FBCommon.GetFBLineIpyData(mapID, funcLineID, False)
+ if fbIpyData:
+ if not fbLineIpyData:
+ GameWorld.DebugLog("不存在该副本功能线路! mapID=%s,funcLineID=%s" % (mapID, funcLineID))
+ return
+ if FBCommon.CheckCanEnterFBComm(curPlayer, mapID, funcLineID, fbIpyData, fbLineIpyData) != ShareDefine.EntFBAskRet_OK:
+ return
+
+ # 攻防方所使用的阵容ID
+ atkLineupID, defLineupID = FBLogic.GetFBPlayerLineupID(curPlayer, mapID, funcLineID)
+ if atkLineupID not in ShareDefine.LineupList or defLineupID not in ShareDefine.LineupList:
+ return
+
+ if CheckFightCD(curPlayer, tick, "TurnFightReqTick"):
+ return
+
+ # 玩家
+ if tagType == 1:
+ if not OnTurnFightVSPlayer(curPlayer, mapID, funcLineID, atkLineupID, defLineupID, tagID):
+ return
+
+ # NPC
+ else:
+ npcLineupIDList, strongerLV, difficulty = [], 0, 0
+ if fbLineIpyData:
+ npcLineupIDList = fbLineIpyData.GetLineupIDList()
+ strongerLV = fbLineIpyData.GetNPCLV()
+ difficulty = fbLineIpyData.GetDifficulty()
+
+ if not npcLineupIDList:
+ ret = FBLogic.GetFBNPCLineupInfo(curPlayer, mapID, funcLineID)
+ if not ret:
+ return
+ npcLineupIDList, strongerLV, difficulty = ret
+ if not OnTurnFightVSNPC(curPlayer, mapID, funcLineID, atkLineupID, npcLineupIDList, strongerLV, difficulty):
+ return
+
+ return True
+
+def OnTurnFightVSNPC(curPlayer, mapID, funcLineID, atkLineupID, npcLineupIDList, strongerLV, difficulty):
+ playerID = curPlayer.GetPlayerID()
+ GameWorld.DebugLog("OnTurnFightVSNPC: mapID=%s,funcLineID=%s,atkLineupID=%s,npcLineupIDList=%s,strongerLV=%s,difficulty=%s"
+ % (mapID, funcLineID, atkLineupID, npcLineupIDList, strongerLV, difficulty), playerID)
+ if not npcLineupIDList:
+ return
+
+ lineupMainInfo = GetPlayerLineupInfo(curPlayer, atkLineupID)
+ if not lineupMainInfo:
+ GameWorld.DebugLog("玩家没有该阵容数据! atkLineupID=%s" % atkLineupID, playerID)
+ return
+
+ turnMax = GetTurnMax(mapID)
+ if mapID == ChConfig.Def_FBMapID_MainBoss:
+ # 停止主线小怪战斗、清空
+ mainFightMgr = GetMainFightMgr(curPlayer)
+ mainTF = mainFightMgr.turnFight
+ if mainTF.isInFight():
+ mainTF.exitFight()
+
+ tfMgr = GetTurnFightMgr()
+ turnFight = tfMgr.addTurnFight(mapID, funcLineID, playerID)
+ guid = turnFight.guid
+
+ turnFight.setTurnFight(mapID, funcLineID, turnMax, True)
+ turnFight.setPVE(npcLineupIDList, strongerLV, difficulty)
+ turnFight.setFactionLineup(ChConfig.Def_FactionA, {1:lineupMainInfo})
+
+ for index, lineupID in enumerate(npcLineupIDList):
+ turnFight.lineupIndex = index
+ GameWorld.DebugLog("对战NPC阵容: index=%s, lineupID=%s" % (index, lineupID))
+ if index > 0:
+ turnFight.nextTurnFight()
+ turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:GetNPCLineupInfo(lineupID, strongerLV, difficulty)})
+ turnFight.sortActionQueue()
+ turnFight.startFight()
+
+ __processTurnFight(turnFight.guid)
+
+ if not turnFight.isWin:
+ break
+
+ PlayerOnline.GetOnlinePlayer(curPlayer).SetLastBatBuffer(guid, turnFight.batBuffer)
+ SyncTurnFightReport(curPlayer, guid, turnFight.batBuffer)
+ FBLogic.OnTurnFightAward(curPlayer, turnFight, mapID, funcLineID, turnFight.awardData)
+ tfMgr.delTurnFight(guid)
+ return True
+
+def OnTurnFightVSPlayer(curPlayer, mapID, funcLineID, atkLineupID, defLineupID, tagPlayerID):
+ playerID = curPlayer.GetPlayerID()
+ GameWorld.DebugLog("OnTurnFightVSPlayer: mapID=%s,funcLineID=%s,atkLineupID=%s,defLineupID=%s,tagPlayerID=%s"
+ % (mapID, funcLineID, atkLineupID, defLineupID, tagPlayerID), playerID)
+ atkLineupInfo = GetPlayerLineupInfo(curPlayer, atkLineupID)
+ if not atkLineupInfo:
+ GameWorld.DebugLog("玩家没有该阵容数据! atkLineupID=%s" % atkLineupID, playerID)
+ return
+
+ tagViewCache = PlayerViewCache.FindViewCache(tagPlayerID)
+ if not tagViewCache:
+ GameWorld.DebugLog("目标玩家没有缓存数据! tagPlayerID=%s" % tagPlayerID, playerID)
+ return {}
+ defLineupInfo = GetCacheLineupInfo(tagViewCache, defLineupID)
+ if not defLineupInfo:
+ GameWorld.DebugLog("目标玩家没有该阵容数据! tagPlayerID=%s,defLineupID=%s" % (tagPlayerID, defLineupID), playerID)
+ return
+
+ turnMax = GetTurnMax(mapID)
+
+ tfMgr = GetTurnFightMgr()
+ turnFight = tfMgr.addTurnFight(mapID, funcLineID, playerID)
+ guid = turnFight.guid
+
+ turnFight.setTurnFight(mapID, funcLineID, turnMax, True)
+ turnFight.setPVP(tagPlayerID, tagViewCache)
+ turnFight.setFactionLineup(ChConfig.Def_FactionA, {1:atkLineupInfo})
+ turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:defLineupInfo})
+ turnFight.sortActionQueue()
+ turnFight.startFight()
+
+ __processTurnFight(turnFight.guid)
+
+ PlayerOnline.GetOnlinePlayer(curPlayer).SetLastBatBuffer(guid, turnFight.batBuffer)
+ SyncTurnFightReport(curPlayer, guid, turnFight.batBuffer)
+ FBLogic.OnTurnFightAward(curPlayer, turnFight, mapID, funcLineID, turnFight.awardData)
+ tfMgr.delTurnFight(guid)
+ return True
+
+def GetTurnMax(mapID):
+ if mapID == ChConfig.Def_FBMapID_Main:
+ return IpyGameDataPY.GetFuncCfg("TurnMax", 1)
+ mapTurnMaxDict= IpyGameDataPY.GetFuncEvalCfg("TurnMax", 3, {})
+ return mapTurnMaxDict.get(mapID, IpyGameDataPY.GetFuncCfg("TurnMax", 2))
#// B4 13 主线战斗请求 #tagCSMainFightReq
#
#struct tagCSMainFightReq
#{
# tagHead Head;
-# BYTE ReqType; // 0-停止战斗回城;1-设置消耗倍值;2-挑战关卡小怪;3-挑战关卡boss;4-继续战斗;
+# BYTE ReqType; // 0-停止战斗回城;1-设置消耗倍值;2-挑战关卡小怪;4-继续战斗;
# DWORD ReqValue; // 请求值,ReqType为1时发送消耗倍值
#};
def OnMainFightReq(index, clientData, tick):
@@ -742,14 +1083,13 @@
__doSetFightPoint(curPlayer, reqValue)
return
+ GameWorld.DebugLog("------------------- 主线战斗请求: reqType=%s" % reqType, curPlayer.GetPlayerID())
clientPack = ChPyNetSendPack.tagSCTurnFightReportSign()
clientPack.Sign = 0
NetPackCommon.SendFakePack(curPlayer, clientPack) # 标记开始
if reqType == 2: # 前端主动请求开始关卡小怪的视为从休息中开始
__doMainLevelWave(curPlayer, True)
- elif reqType == 3:
- __doMainBossStart(curPlayer)
elif reqType == 4:
__doMainFight(curPlayer, tick)
else:
@@ -765,7 +1105,7 @@
mainFightMgr = GetMainFightMgr(curPlayer)
turnFight = mainFightMgr.turnFight
if turnFight:
- turnFight.exitFight()
+ turnFight.exitFight(True)
return
def __doSetFightPoint(curPlayer, fightPoint):
@@ -789,9 +1129,6 @@
# @param isRestStart: 是否从休息状态重新开始的
playerID = curPlayer.GetPlayerID()
chapterID, levelNum, wave = PlayerControl.GetMainLevelNowInfo(curPlayer)
- if not chapterID and not levelNum:
- PlayerControl.SetMainLevelNowInfo(curPlayer, 1, 1, 1)
- chapterID, levelNum, wave = PlayerControl.GetMainLevelNowInfo(curPlayer)
GameWorld.DebugLog("请求关卡波战斗: chapterID=%s,levelNum=%s,wave=%s,isRestStart=%s" % (chapterID, levelNum, wave, isRestStart), playerID)
fightPoint = max(curPlayer.GetFightPoint(), 1)
if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
@@ -820,12 +1157,10 @@
if wave > waveMax:
wave = waveMax
- waveLineupList = getattr(levelIpyData, "GetWaveLineupIDList%s" % wave)() # 小队1阵容ID|小队2阵容ID|...
- if not waveLineupList:
+ lineupIDList = getattr(levelIpyData, "GetWaveLineupIDList%s" % wave)() # 小队1阵容ID|小队2阵容ID|...
+ if not lineupIDList:
return
- teamMax = len(waveLineupList)
- teamNum = 1
- lineupID = waveLineupList[teamNum - 1] # NPC阵容ID
+ lineupID = lineupIDList[0] # NPC阵容ID
lineupMainInfo = GetPlayerLineupInfo(curPlayer, ShareDefine.Lineup_Main)
if not lineupMainInfo:
@@ -835,280 +1170,153 @@
strongerLV = levelIpyData.GetNPCLV()
difficulty = levelIpyData.GetDifficulty()
mainFightMgr = GetMainFightMgr(curPlayer)
- mainFightMgr.nextTeam = False
mainFightMgr.chapterID = chapterID
mainFightMgr.levelNum = levelNum
mainFightMgr.waveMax = waveMax
mainFightMgr.wave = wave
- mainFightMgr.waveLineupList = waveLineupList
- mainFightMgr.teamNum = teamNum
- mainFightMgr.teamMax = teamMax
- mainFightMgr.strongerLV = strongerLV
- mainFightMgr.difficulty = difficulty
- turnMax = IpyGameDataPY.GetFuncCfg("Mainline", 2)
mapID, funcLineID = ChConfig.Def_FBMapID_Main, PlayerControl.ComMainLevelValue(chapterID, levelNum, wave)
- GameWorld.DebugLog("设置起始关卡波: 关卡%s-%s,波=%s/%s,teamMax=%s,mapID=%s,funcLineID=%s,lineupID=%s,strongerLV=%s,difficulty=%s"
- % (chapterID, levelNum, wave, waveMax, teamMax, mapID, funcLineID, lineupID, strongerLV, difficulty), playerID)
+ turnMax = GetTurnMax(mapID)
+ GameWorld.DebugLog("设置起始关卡波: 关卡%s-%s,波=%s/%s,lineupIDList=%s,mapID=%s,funcLineID=%s,lineupID=%s,strongerLV=%s,difficulty=%s"
+ % (chapterID, levelNum, wave, waveMax, lineupIDList, mapID, funcLineID, lineupID, strongerLV, difficulty), playerID)
turnFight = mainFightMgr.turnFight
- turnFight.setTurn(mapID, funcLineID, turnMax, False, {"teamNum":teamNum, "teamMax":teamMax})
- turnFight.setFactionLineup(ChConfig.Def_FactionA, {1:lineupMainInfo})
- turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:GetNPCLineupInfo(lineupID, strongerLV, difficulty)})
- turnFight.sortActionQueue()
- turnFight.startFight()
- return
-
-def __doMainBossStart(curPlayer):
- ## 开始挑战关卡boss
- playerID = curPlayer.GetPlayerID()
- chapterID, levelNum, wave = PlayerControl.GetMainLevelPassInfo(curPlayer)
- if not chapterID:
- chapterID = 1
- if not levelNum:
- levelNum = 1
- GameWorld.DebugLog("请求挑战关卡Boss! passInfo: chapterID=%s,levelNum=%s,wave=%s" % (chapterID, levelNum, wave), playerID)
- chapterIpyData = IpyGameDataPY.GetIpyGameData("MainChapter", chapterID)
- if not chapterIpyData:
- return
- levelIpyData = IpyGameDataPY.GetIpyGameData("MainLevel", chapterID, levelNum)
- if not levelIpyData:
- return
-
- nowChapterID, nowLevelNum, _ = PlayerControl.GetMainLevelNowInfo(curPlayer)
- if chapterID != nowChapterID or levelNum != nowLevelNum:
- '''一般有两种情况会导致
- 1. 理论上玩家当前刷怪的章节关卡一定是与过关的章节关卡是一致的,除了全部章节已通关
- 当通关时,已过关的记录会被设置为下一章节第1关(版本关卡表实际不存在该关卡)
- 但是当前刷怪的还是版本的最后一关,固会出现不一致的情况
- 在增加章节关卡新版本更新后玩家重登会自动进行修复当前刷怪进度为最新章节第1关
- 2. 真的出现问题了,可能是bug引起,这种情况只能进行bug修复及针对异常账号特殊处理,或者重登后也会自动进行修正
- '''
- GameWorld.ErrLog("当前刷怪章节关卡与挑战的boss章节关卡不一致,无法挑战! chapterID=%s,levelNum=%s,nowChapterID=%s,nowLevelNum=%s"
- % (chapterID, levelNum, nowChapterID, nowLevelNum), playerID)
- return
-
- # 本关卡最大波数
- waveMax = 6
- while waveMax >= 1 and (not hasattr(levelIpyData, "GetWaveLineupIDList%s" % waveMax) or not getattr(levelIpyData, "GetWaveLineupIDList%s" % waveMax)()):
- waveMax -= 1
-
- if wave < waveMax:
- GameWorld.DebugLog("最后一波未通过,无法挑战本关boss! passWave=%s < %s" % (wave, waveMax))
- return
-
- waveLineupList = levelIpyData.GetBossLineupIDList() # Boss波阵容ID列表,小队1阵容ID|小队2阵容ID|...
- if not waveLineupList:
- return
- teamMax = len(waveLineupList)
- teamNum = 1
- lineupID = waveLineupList[teamNum - 1] # NPC阵容ID
-
- wave = waveMax = 1 # 关卡boss固定只有一波
-
- lineupMainInfo = GetPlayerLineupInfo(curPlayer, ShareDefine.Lineup_Main)
- if not lineupMainInfo:
- GameWorld.DebugLog("没有设置主阵容!", playerID)
- return
-
- strongerLV = levelIpyData.GetNPCLV()
- difficulty = levelIpyData.GetDifficulty()
- mainFightMgr = GetMainFightMgr(curPlayer)
- mainFightMgr.nextTeam = False
- mainFightMgr.chapterID = chapterID
- mainFightMgr.levelNum = levelNum
- mainFightMgr.waveMax = waveMax
- mainFightMgr.wave = wave
- mainFightMgr.waveLineupList = waveLineupList
- mainFightMgr.teamNum = teamNum
- mainFightMgr.teamMax = teamMax
- mainFightMgr.strongerLV = strongerLV
- mainFightMgr.difficulty = difficulty
- turnMax = IpyGameDataPY.GetFuncCfg("Mainline", 3)
- mapID, funcLineID = ChConfig.Def_FBMapID_MainBoss, PlayerControl.ComMainLevelValue(chapterID, levelNum, wave)
- GameWorld.DebugLog("设置关卡boss: 关卡%s-%s,波=%s/%s,teamMax=%s,mapID=%s,funcLineID=%s,lineupID=%s,strongerLV=%s,difficulty=%s"
- % (chapterID, levelNum, wave, waveMax, teamMax, mapID, funcLineID, lineupID, strongerLV, difficulty), playerID)
-
- turnFight = mainFightMgr.turnFight
- turnFight.setTurn(mapID, funcLineID, turnMax, False, {"teamNum":teamNum, "teamMax":teamMax})
+ turnFight.setTurnFight(mapID, funcLineID, turnMax, False)
+ turnFight.setPVE(lineupIDList, strongerLV, difficulty)
turnFight.setFactionLineup(ChConfig.Def_FactionA, {1:lineupMainInfo})
turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:GetNPCLineupInfo(lineupID, strongerLV, difficulty)})
turnFight.sortActionQueue()
turnFight.startFight()
- # 挑战boss无中间过程,每次执行直接挑战一队结果
- __processTurnFight(turnFight.guid)
+ __doMainFight(curPlayer)
return
-def __doMainFight(curPlayer, tick):
- ## 主线执行战斗
+def __doMainFight(curPlayer, tick=0):
+ '''执行主线战斗,单场战斗断电式战斗,以前端玩家手动点击节点做为断点处
+ 每场战斗的初始化、结束默认断点,由前端决定自动继续或者点击继续
+ '''
# 限制请求CD
- #if not GameWorld.GetGameWorld().GetDebugLevel():
- key = "MainFightReqTick"
- lastTick = curPlayer.GetDictByKey(key)
- if lastTick and tick - lastTick <= 1000:
- GameWorld.DebugLog("主线战斗请求CD中")
- return
- curPlayer.SetDict(key, tick)
-
+ if tick:
+ if CheckFightCD(curPlayer, tick, "MainFightReqTick"):
+ return
+
mainFightMgr = GetMainFightMgr(curPlayer)
turnFight = mainFightMgr.turnFight
isLevelBoss = mainFightMgr.isLevelBoss()
- winFaction = turnFight.winFaction
- if winFaction:
- if mainFightMgr.nextTeam:
- # 自动开始下一小队
- teamNum = mainFightMgr.teamNum = mainFightMgr.teamNum + 1
- GameWorld.DebugLog("开始进入下一小队: teamNum=%s" % teamNum)
- if teamNum < 1 or teamNum > len(mainFightMgr.waveLineupList):
- return
- lineupID = mainFightMgr.waveLineupList[teamNum - 1] # NPC阵容ID
- GameWorld.DebugLog("teamNum=%s,lineupID=%s" % (teamNum, lineupID))
-
- mainFightMgr.nextTeam = False
- turnFight.resetTurn({"teamNum":teamNum})
- # 切换小队时,玩家阵容不需要处理,保留状态
- turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:GetNPCLineupInfo(lineupID, mainFightMgr.strongerLV, mainFightMgr.difficulty)})
- turnFight.sortActionQueue()
- turnFight.startFight()
-
- if mainFightMgr.isLevelBoss():
- # 每次处理一小队的完整战斗,相当于一次完整战报
- __processTurnFight(turnFight.guid)
- return
- else:
- __doMainLevelWave(curPlayer, False)
- return
-
if isLevelBoss:
## 关卡boss是一次性处理完的,一般不可能走到这里,这边做下防范
return
+ if not turnFight.isInFight():
+ __doMainLevelWave(curPlayer, True)
+ return
+
+ winFaction = turnFight.winFaction
+ if winFaction:
+ nextLineupID = turnFight.nextLineupID()
+ if nextLineupID:
+ GameWorld.DebugLog("---开始进入下一小队: lineupIndex=%s,nextLineupID=%s,%s" % (turnFight.lineupIndex, nextLineupID, turnFight.lineupIDList))
+
+ turnFight.nextTurnFight()
+ # 切换小队时,玩家阵容不需要处理,保留状态
+ turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:GetNPCLineupInfo(nextLineupID, turnFight.strongerLV, turnFight.difficulty)})
+ turnFight.sortActionQueue()
+ turnFight.startFight()
+
+ __doMainFight(curPlayer)
+ else:
+ __doMainLevelWave(curPlayer, False)
+ return
+
# 小怪战斗,每次消耗1个战锤
fightPoint = max(curPlayer.GetFightPoint(), 1) # 主线战斗消耗倍值,默认1
-
if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
GameWorld.DebugLog("回合开始时战锤不足!")
return
# 以下均是处理关卡小怪分段实时战斗
- EntryLogic(turnFight)
+ isEntry = EntryLogic(turnFight)
- # 按阵营阵容执行顺序,逐个遍历
- doCnt = 0
- doMax = (PosNumMax + 2) * len(turnFight.actionSortList) # 防止死循环,做最大循环次数限制 = (最大位置数 + 主公、红颜位置)*行动阵容数
- overLineupList = [] # 本回合已经结束行动的阵容列表 [(faction, num), ...], 所有阵容全部结束代表本回合结束
+ # 是否开始检查断点,预判可断的点,方便前端点击体验,点下去就是玩家放的某个行动
+ # 初始开始进场后,默认开始断点
+ checkBreakpoint = True if isEntry else False
batObjMgr = BattleObj.GetBatObjMgr()
turnNum = turnFight.turnNum
- GameWorld.DebugLog("turnNum=%s,doMax=%s,actionIndex=%s,%s" % (turnNum, doMax, turnFight.actionIndex, turnFight.actionSortList))
- while doCnt < doMax and len(overLineupList) < len(turnFight.actionSortList):
- doCnt += 1
- turnNum = turnFight.turnNum
- # 执行回合开始逻辑
- if turnFight.turnStart < turnNum:
- GameWorld.DebugLog("执行行动: turnNum=%s, 回合开始" % (turnFight.turnNum))
- turnFight.syncState(FightState_Fighting)
- #if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
- # GameWorld.DebugLog("回合开始时战锤不足!")
- # return
- turnFight.turnStart = turnNum
- turnFight.actionIndex = 0
- turnFight.addTimeline() # 每回合开始算一个时间节点
- for faction, num in turnFight.actionSortList:
- batFaction = turnFight.getBatFaction(faction)
- batLineup = batFaction.getBatlineup(num)
- batLineup.actionNum = ActionNumStart
- for objID in batLineup.posObjIDDict.values():
- batObj = batObjMgr.getBatObj(objID)
- TurnFightPerTurnBigStart(turnFight, batObj, turnNum)
-
- if turnFight.actionIndex >= len(turnFight.actionSortList):
- turnFight.actionIndex = 0
+ turnMax = turnFight.turnMax
+ turnNumStart = turnFight.turnNumStart
+ for turnNum in range(turnNum, turnMax + 1):
+ if turnFight.winFaction:
+ break
+
+ # 回合开始
+ if turnNumStart < turnNum:
+ GameWorld.DebugLog("【----- 回合制战斗轮次: %s -----】 " % (turnNum))
+ turnFight.turnNum = turnNum
+ turnFight.turnNumStart = turnNum
+ if curPlayer:
+ turnFight.syncState(FightState_Fighting)
+ TurnFightPerTurnBigStart(turnFight, turnNum)
- playerHeroAtk = False # 玩家阵容行动标记
- faction, num = turnFight.actionSortList[turnFight.actionIndex]
- batFaction = turnFight.getBatFaction(faction)
- batLineup = batFaction.getBatlineup(num)
- if batLineup.actionNum > max(batLineup.posObjIDDict):
- if (faction, num) not in overLineupList:
- overLineupList.append((faction, num))
-
- turnFight.actionIndex += 1
- continue
-
- GameWorld.DebugLog("执行行动: turnNum=%s,faction=%s,num=%s,actionNum=%s" % (turnFight.turnNum, faction, num, batLineup.actionNum))
-
- # 主公
- if batLineup.actionNum == -1:
- pass
-
# 红颜
- elif batLineup.actionNum == 0:
- pass
+ # 灵兽
+
+ if turnFight.winFaction:
+ break
# 武将
- elif batLineup.actionNum > 0:
+ doMax = PosNumMax * len(turnFight.actionSortList)
+ doCnt = 0
+ while doCnt < doMax and turnFight.actionIndex < len(turnFight.actionSortList) and not turnFight.winFaction:
+ doCnt += 1
+ faction, num = turnFight.actionSortList[turnFight.actionIndex]
+ batFaction = turnFight.getBatFaction(faction)
+ batLineup = batFaction.getBatlineup(num)
for posNum in range(batLineup.actionNum, PosNumMax + 1):
- turnFight.addTimeline() # 每个武将位算一个时间节点
- batLineup.actionNum = posNum
+ #GameWorld.DebugLog("武将位置: faction=%s,posNum=%s" % (faction, posNum))
if posNum not in batLineup.posObjIDDict:
- continue
- objID = batLineup.posObjIDDict[posNum]
- batObj = batObjMgr.getBatObj(objID)
- TurnFightHeroTurnStart(turnFight, batObj, turnNum)
- if not OnObjAction(turnFight, batObj):
+ batLineup.actionNum = posNum + 1
+ #GameWorld.DebugLog("没有武将: faction=%s,posNum=%s" % (faction, posNum))
continue
- if faction == ChConfig.Def_FactionA:
- playerHeroAtk = True
+ objID = batLineup.posObjIDDict[posNum]
+ batObj = batObjMgr.getBatObj(objID)
+
+ # 玩家自己阵营,预判可否行动
+ if checkBreakpoint and faction == ChConfig.Def_FactionA and batObj:
+ if batObj.CanAction():
+ GameWorld.DebugLog("玩家阵容下一个可行动的武将,断点: nextPosNum=%s" % (posNum))
+ return
+
+ batLineup.actionNum = posNum + 1
+
+ TurnFightHeroTurnStart(turnFight, batObj, turnNum)
+ isAction = OnObjAction(turnFight, batObj)
+ TurnFightHeroTurnEnd(turnFight, batObj, turnNum)
+
+ if not isAction:
+ continue
+
+ if not checkBreakpoint and faction == ChConfig.Def_FactionA:
+ checkBreakpoint = True
break
- turnFight.actionIndex += 1
- batLineup.actionNum += 1
- if batLineup.actionNum > max(batLineup.posObjIDDict):
- GameWorld.DebugLog("该阵容本回合已经全部行动完了: turnNum=%s,faction=%s,num=%s,actionNum=%s" % (turnFight.turnNum, faction, num, batLineup.actionNum))
- if (faction, num) not in overLineupList:
- overLineupList.append((faction, num))
+ if turnFight.actionIndex >= len(turnFight.actionSortList) - 1:
+ turnFight.actionIndex = 0
+ else:
+ turnFight.actionIndex += 1
- if turnFight.checkOverByKilled():
+ if turnFight.winFaction:
break
- if playerHeroAtk:
- # 玩家武将有行动则停止,一段段执行
- GameWorld.DebugLog("玩家武将有行动则停止!")
- break
+ # 回合结束
+ TurnFightPerTurnBigEnd(turnFight, turnNum)
- if turnFight.winFaction:
- return
-
- GameWorld.DebugLog("turnNum=%s,doCnt=%s,overLineupList=%s" % (turnNum, doCnt, overLineupList))
- if len(overLineupList) >= len(turnFight.actionSortList):
- GameWorld.DebugLog("执行行动: turnNum=%s, 回合结束" % (turnFight.turnNum))
- if turnFight.turnEnd < turnNum:
- #if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
- # GameWorld.DebugLog("回合结束时战锤不足!")
- # return
- turnFight.turnEnd = turnNum
- turnFight.addTimeline() # 每回合结束算一个时间节点
- for faction, num in turnFight.actionSortList:
- batFaction = turnFight.getBatFaction(faction)
- batLineup = batFaction.getBatlineup(num)
- for objID in batLineup.posObjIDDict.values():
- batObj = batObjMgr.getBatObj(objID)
- TurnFightPerTurnBigEnd(turnFight, batObj, turnNum)
-
- if turnFight.checkOverByKilled():
- return
-
- if turnNum < turnFight.turnMax:
- turnFight.turnNum += 1
- turnFight.setTimeline(turnFight.turnNum) # 回合变更,直接设置新回合时间节点
- else:
- OnTurnAllOver(turnFight.guid)
-
+ if not turnFight.winFaction:
+ OnTurnAllOver(turnFight.guid)
+
return
def __processTurnFight(guid):
@@ -1119,57 +1327,41 @@
EntryLogic(turnFight)
batObjMgr = BattleObj.GetBatObjMgr()
for turnNum in range(1, turnMax + 1):
+ if turnFight.winFaction:
+ break
turnFight.turnNum = turnNum
GameWorld.DebugLog("【----- 回合制战斗轮次: %s -----】" % turnNum)
- turnFight.setTimeline(turnNum)
if curPlayer:
turnFight.syncState(FightState_Fighting)
# 回合开始
- turnFight.addTimeline() # 每回合开始算一个时间节点
- for faction, num in turnFight.actionSortList:
- GameWorld.DebugLog("回合开始逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
- batFaction = turnFight.getBatFaction(faction)
- batLineup = batFaction.getBatlineup(num)
- batLineup.actionNum = 1
- for objID in batLineup.posObjIDDict.values():
- batObj = batObjMgr.getBatObj(objID)
- TurnFightPerTurnBigStart(turnFight, batObj, turnNum)
-
- # 主公
- #for faction, num in turnFight.actionSortList:
- # GameWorld.DebugLog("主公逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
- # batFaction = turnFight.getBatFaction(faction)
- # batLineup = batFaction.getBatlineup(num)
-
+ TurnFightPerTurnBigStart(turnFight, turnNum)
+
# 红颜
- #for faction, num in turnFight.actionSortList:
- # GameWorld.DebugLog("红颜逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
- # batFaction = turnFight.getBatFaction(faction)
- # batLineup = batFaction.getBatlineup(num)
+ # 灵兽
- if turnFight.checkOverByKilled():
+ if turnFight.winFaction:
break
# 武将
doMax = PosNumMax * len(turnFight.actionSortList)
doCnt = 0
- while doCnt < doMax and turnFight.actionIndex < len(turnFight.actionSortList):
+ while doCnt < doMax and turnFight.actionIndex < len(turnFight.actionSortList) and not turnFight.winFaction:
doCnt += 1
faction, num = turnFight.actionSortList[turnFight.actionIndex]
batFaction = turnFight.getBatFaction(faction)
batLineup = batFaction.getBatlineup(num)
for posNum in range(batLineup.actionNum, PosNumMax + 1):
- turnFight.addTimeline() # 每个武将位算一个时间节点
batLineup.actionNum = posNum + 1
if posNum not in batLineup.posObjIDDict:
continue
objID = batLineup.posObjIDDict[posNum]
batObj = batObjMgr.getBatObj(objID)
TurnFightHeroTurnStart(turnFight, batObj, turnNum)
- if not OnObjAction(turnFight, batObj):
+ isAction = OnObjAction(turnFight, batObj)
+ TurnFightHeroTurnEnd(turnFight, batObj, turnNum)
+ if not isAction:
continue
-
break
if turnFight.actionIndex >= len(turnFight.actionSortList) - 1:
@@ -1177,18 +1369,11 @@
else:
turnFight.actionIndex += 1
- # 回合结束
- turnFight.addTimeline() # 每回合结束算一个时间节点
- for faction, num in turnFight.actionSortList:
- GameWorld.DebugLog("回合结束逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
- batFaction = turnFight.getBatFaction(faction)
- batLineup = batFaction.getBatlineup(num)
- for objID in batLineup.posObjIDDict.values():
- batObj = batObjMgr.getBatObj(objID)
- TurnFightPerTurnBigEnd(turnFight, batObj, turnNum)
-
- if turnFight.checkOverByKilled():
+ if turnFight.winFaction:
break
+
+ # 回合结束
+ TurnFightPerTurnBigEnd(turnFight, turnNum)
if not turnFight.winFaction:
OnTurnAllOver(turnFight.guid)
@@ -1220,131 +1405,168 @@
batLineup.actionNum = ActionNumStart
for objID in batLineup.posObjIDDict.values():
batObj = batObjMgr.getBatObj(objID)
+ turnFight.ResetOneActionUseSkillCnt()
TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_FightStart)
turnFight.enterLogic = True
- return
+ return True
-def OnTimelineChange(turnFight):
- ## 每个时间节点变化时处理
-
- nowTimeline = turnFight.getTimeline()
+def TurnFightPerTurnBigStart(turnFight, turnNum):
+ ## 大回合开始时
batObjMgr = BattleObj.GetBatObjMgr()
- for batFaction in turnFight.factionDict.values():
- for batLineup in batFaction.lineupDict.values():
- for objID in batLineup.posObjIDDict.values():
- batObj = batObjMgr.getBatObj(objID)
- #GameWorld.DebugLog("OnTimelineChange! objID=%s" % (objID))
- if not batObj or not batObj.IsAlive():
- continue
+ for faction, num in turnFight.actionSortList:
+ GameWorld.DebugLog("大回合开始逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
+ batFaction = turnFight.getBatFaction(faction)
+ batLineup = batFaction.getBatlineup(num)
+ batLineup.actionNum = 1
+ for objID in batLineup.posObjIDDict.values():
+ batObj = batObjMgr.getBatObj(objID)
+ if not batObj:
+ continue
+ if not batObj.IsAlive():
+ continue
+
+ turnFight.ResetOneActionUseSkillCnt()
+ batObj.SetTiming(ChConfig.TurnTiming_Before) # 重置时机到回合前
+ if turnNum > 1: # 第1回合不用刷新技能
+ RefreshObjSkillByTurn(batObj)
- batObj.SetDict(ChConfig.Def_Obj_Dict_TurnComboNum, 0)
- batObj.SetDict(ChConfig.Def_Obj_Dict_TurnMissNum, 0)
- batObj.SetDict(ChConfig.Def_Obj_Dict_TurnParryNum, 0)
-
- curID = batObj.GetID()
- skillManager = batObj.GetSkillManager()
- for index in range(0, skillManager.GetSkillCount()):
- curSkill = skillManager.GetSkillByIndex(index)
- if not curSkill:
- continue
- remainTime = curSkill.GetRemainTime()
- if not remainTime:
- continue
- calcTimeline = curSkill.GetCalcTime()
- passTurn = __calcPassturn(calcTimeline, nowTimeline, True)
- if passTurn <= 0:
- continue
- skillID = curSkill.GetSkillID()
- updRemainTime = max(0, remainTime - passTurn)
- curSkill.SetRemainTime(updRemainTime)
- curSkill.SetCalcTime(nowTimeline)
- GameWorld.DebugLog("更新技能剩余回合数: curID=%s,skillID=%s,updRemainTime=%s,calcTimeline=%s,passTurn=%s"
- % (curID, skillID, updRemainTime, calcTimeline, passTurn))
-
- buffMgr = batObj.GetBuffManager()
- for index in range(buffMgr.GetBuffCount())[::-1]:
- buff = buffMgr.GetBuffByIndex(index)
- buffID = buff.GetBuffID()
- skillID = buff.GetSkillID()
- skillData = buff.GetSkillData()
- if skillData.GetSkillType() in ChConfig.Def_LstBuff_List:
- #GameWorld.DebugLog(" 持续类buff由触发时机决定剩余时间! curID=%s,index=%s,skillID=%s,buffID=%s" % (curID, index, skillID, buffID))
- continue
- remainTime = buff.GetRemainTime()
- if not remainTime:
- # 永久buff不处理
- #GameWorld.DebugLog(" 永久buff不处理! curID=%s,index=%s,skillID=%s" % (curID, index, skillID))
- continue
- calcTimeline = buff.GetCalcTime()
- passTurn = __calcPassturn(calcTimeline, nowTimeline, False)
- if passTurn <= 0:
- #GameWorld.DebugLog(" passTurn <= 0 passTurn=%s,calcTimeline=%s,nowTimeline=%s,skillID=%s" % (passTurn, calcTimeline, nowTimeline, skillID))
- continue
-
- updRemainTime = max(0, remainTime - passTurn)
- GameWorld.DebugLog("更新buff剩余回合数: curID=%s,buffID=%s,skillID=%s,updRemainTime=%s,calcTimeline=%s,passTurn=%s"
- % (curID, buffID, skillID, updRemainTime, calcTimeline, passTurn))
- if updRemainTime > 0:
- buff.SetRemainTime(updRemainTime)
- buff.SetCalcTime(nowTimeline)
- TurnBuff.SyncBuffRefresh(turnFight, batObj, buff)
- else:
- TurnBuff.DoBuffDel(turnFight, batObj, buff)
-
+ TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_BigTurnStart)
+
return
-def __calcPassturn(calcTimeline, nowTimeline, equalOK):
- ## 计算已经过了的回合数
- # @param equalOK: 时间节点相同时是否算1回合,一般技能可以算,buff不算
- calcTurnNum = calcTimeline / TimelineSet
- calcTimeNode = calcTimeline % TimelineSet
- nowTurnNum = nowTimeline / TimelineSet
- nowTimeNode = nowTimeline % TimelineSet
- if equalOK:
- if nowTimeNode >= calcTimeNode:
- return max(0, nowTurnNum - calcTurnNum)
- return max(0, nowTurnNum - calcTurnNum - 1)
- else:
- if nowTimeNode > calcTimeNode:
- return max(0, nowTurnNum - calcTurnNum)
- return max(0, nowTurnNum - calcTurnNum - 1)
- return 0
-
-def TurnFightPerTurnBigStart(turnFight, batObj, turnNum):
- ## 大回合开始时
- if not batObj:
- return
-
- if batObj.GetHP() <= 0:
- return
-
- TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_BigTurnStart)
- return
-
-def TurnFightPerTurnBigEnd(turnFight, batObj, turnNum):
+def TurnFightPerTurnBigEnd(turnFight, turnNum):
## 大回合结束时
- if not batObj:
- return
- if batObj.GetHP() <= 0:
- return
-
- TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_BigTurnEnd)
+ batObjMgr = BattleObj.GetBatObjMgr()
+ for faction, num in turnFight.actionSortList:
+ GameWorld.DebugLog("回合结束逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
+ batFaction = turnFight.getBatFaction(faction)
+ batLineup = batFaction.getBatlineup(num)
+ for objID in batLineup.posObjIDDict.values():
+ batObj = batObjMgr.getBatObj(objID)
+ if not batObj:
+ continue
+ if not batObj.IsAlive():
+ continue
+
+ turnFight.ResetOneActionUseSkillCnt()
+ TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_BigTurnEnd)
+
return
def TurnFightHeroTurnStart(turnFight, batObj, turnNum):
- ## 武将回合开始时
+ ## 武将回合开始时,不能行动也要触发
if not batObj:
return
- if batObj.GetHP() <= 0:
+ if not batObj.IsAlive():
return
+ GameWorld.DebugLog("---[武将回合开始] : curID=%s,curHP=%s/%s" % (batObj.GetID(), batObj.GetHP(), batObj.GetMaxHP()))
+ turnFight.ResetOneActionUseSkillCnt()
+ RefreshObjBuffTime(turnFight, batObj)
TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_HeroTurnStart)
+
+ # 最后设置时机为回合后,说明:回合开启前的逻辑处理完后,其他的均默认为回合后
+ batObj.SetTiming(ChConfig.TurnTiming_After)
return
+def TurnFightHeroTurnEnd(turnFight, batObj, turnNum):
+ ## 武将回合结束时,不能行动也要触发
+ if not batObj:
+ return
+
+ if not batObj.IsAlive():
+ return
+
+ GameWorld.DebugLog("---[武将回合结束] : curID=%s,curHP=%s/%s" % (batObj.GetID(), batObj.GetHP(), batObj.GetMaxHP()))
+ turnFight.ResetOneActionUseSkillCnt()
+ RefreshObjBuffTime(turnFight, batObj)
+ return
+
+def ResetObjSkill(batObj):
+ ## 重置所有技能,一般是每场战斗开始的重置
+ curID = batObj.GetID()
+ batObj.ResetSkillUseCnt() # 使用次数
+ skillManager = batObj.GetSkillManager()
+ for index in range(0, skillManager.GetSkillCount()):
+ curSkill = skillManager.GetSkillByIndex(index)
+ if not curSkill:
+ continue
+ skillID = curSkill.GetSkillID()
+ initCD = curSkill.GetCoolDownInit()
+ if initCD:
+ curSkill.SetRemainTime(initCD)
+ GameWorld.DebugLog("技能初始CD: curID=%s,skillID=%s,initCD=%s" % (curID, skillID, initCD))
+ elif curSkill.GetRemainTime():
+ curSkill.SetRemainTime(0)
+ curSkill.SetEnergy(0)
+
+ return
+
+def RefreshObjSkillByTurn(batObj):
+ '''按回合刷新技能:默认以大回合统一减1回合
+ '''
+ curID = batObj.GetID()
+ skillManager = batObj.GetSkillManager()
+ for index in range(0, skillManager.GetSkillCount()):
+ curSkill = skillManager.GetSkillByIndex(index)
+ if not curSkill:
+ continue
+ skillID = curSkill.GetSkillID()
+ preTurnUseCnt = batObj.GetSkillTurnUseCnt(skillID)
+ remainTime = curSkill.GetRemainTime()
+ if remainTime <= 0:
+ continue
+ if preTurnUseCnt > 0:
+ GameWorld.DebugLog(" 上回合有使用技能本回合不刷新CD: curID=%s,skillID=%s,remainTime=%s,preTurnUseCnt=%s" % (curID, skillID, remainTime, preTurnUseCnt))
+ continue
+ remainTime -= 1
+ curSkill.SetRemainTime(remainTime)
+ GameWorld.DebugLog(" 更新技能CD: curID=%s,skillID=%s,remainTime=%s" % (curID, skillID, remainTime))
+
+ batObj.ResetSkillTurnUseCnt() # 重置回合使用次数,放刷新CD后重置
+ return
+
+def RefreshObjBuffTime(turnFight, batObj):
+ '''刷新buff持续时间:以武将自身回合前、回合后处理buff持续时间
+ 回合前添加的buff在回合开始减1,回合后添加的buff在回合结束减1
+ '''
+ curID = batObj.GetID()
+ curTiming = batObj.GetTiming() # 时间节点 0-回合前;1-回合后
+ buffMgr = batObj.GetBuffManager()
+ for index in range(buffMgr.GetBuffCount())[::-1]:
+ buff = buffMgr.GetBuffByIndex(index)
+ buffID = buff.GetBuffID()
+ skillID = buff.GetSkillID()
+ skillData = buff.GetSkillData()
+ if skillData.GetSkillType() in ChConfig.Def_LstBuff_List:
+ #GameWorld.DebugLog(" 持续类buff由触发时机决定剩余时间! curID=%s,index=%s,skillID=%s,buffID=%s" % (curID, index, skillID, buffID))
+ continue
+ remainTime = buff.GetRemainTime()
+ if remainTime <= 0:
+ # 永久buff不处理
+ #GameWorld.DebugLog(" 永久buff不处理! curID=%s,index=%s,skillID=%s" % (curID, index, skillID))
+ continue
+ addTiming = buff.GetAddTiming()
+ if not buff.GetRefreshState():
+ GameWorld.DebugLog(" 未刷新过的buff更新为刷新过! curID=%s,index=%s,skillID=%s,buffID=%s,addTiming=%s" % (curID, index, skillID, buffID, addTiming))
+ buff.SetRefreshState(1)
+ continue
+ if addTiming != curTiming:
+ GameWorld.DebugLog(" buff添加时机不同不处理! curID=%s,index=%s,skillID=%s,buffID=%s,addTiming=%s" % (curID, index, skillID, buffID, addTiming))
+ continue
+ remainTime -= 1
+ GameWorld.DebugLog(" 更新buff回合: curID=%s,buffID=%s,skillID=%s,remainTime=%s,addTiming=%s" % (curID, buffID, skillID, remainTime, addTiming))
+ if remainTime > 0:
+ buff.SetRemainTime(remainTime)
+ TurnBuff.SyncBuffRefresh(turnFight, batObj, buff)
+ else:
+ TurnBuff.DoBuffDel(turnFight, batObj, buff)
+ return
+
def AddTurnObjCureHP(curObj, srcObj, addValue, cureHP, skillID=0):
## 回合对象添加治疗值
# @param curObj: 获得治疗的对象
@@ -1384,8 +1606,9 @@
% (curID, tagID, skillID, hurtValue, lostHP, curBatObj.GetHP()))
return
-def OnObjAction(turnFight, curBatObj):
+def OnObjAction(turnFight, curBatObj, isExtra=False):
## 战斗单位行动
+ # @param isExtra: 是否额外行动的
if not curBatObj:
return
@@ -1400,12 +1623,13 @@
# 是否可行动状态判断
canAction = curBatObj.CanAction()
if not canAction:
- GameWorld.DebugLog("★回合%s %s 当前状态不可行动!" % (turnNum, objName))
+ GameWorld.DebugLog("★回合%s %s 当前状态不可行动! isExtra=%s" % (turnNum, objName, isExtra))
return
atk = curBatObj.GetAtk()
curXP = curBatObj.GetXP()
- GameWorld.DebugLog("★回合%s %s 行动 : atk=%s,curHP=%s/%s,curXP=%s" % (turnNum, objName, atk, curHP, curBatObj.GetMaxHP(), curXP))
+ GameWorld.DebugLog("★回合%s %s %s行动 : atk=%s,curHP=%s/%s,curXP=%s" % (turnNum, objName, "额外" if isExtra else "", atk, curHP, curBatObj.GetMaxHP(), curXP))
+ turnFight.ResetOneActionUseSkillCnt()
turnFight.syncObjAction(turnNum, objID)
TurnPassive.OnTriggerPassiveEffect(turnFight, curBatObj, ChConfig.TriggerWay_HeroActionStart)
@@ -1430,13 +1654,16 @@
skillID = useSkill.GetSkillID()
# 常规攻击优先xp
if SkillCommon.isAngerSkill(useSkill):
- if curXP < xpMax:
+ if curXP < xpMax and not useSkill.GetEffectByID(ChConfig.SkillEff_AngerSkillNoXP):
continue
- if curBatObj.IsInState(ChConfig.BatObjState_Sneer):
- GameWorld.DebugLog("嘲讽状态下,无法主动释放怒技!") # 可被动释放怒技,如怒技追击
+ if curBatObj.CheckInState(ChConfig.BatObjState_Sneer):
+ GameWorld.DebugLog("嘲讽状态下,无法主动释放怒技! skillID=%s" % skillID) # 可被动释放怒技,如怒技追击
continue
useCnt = -1 # xp技能优先释放
else:
+ if useSkill.GetEffectByID(ChConfig.SkillEff_ActionUseInvalid): # 配置该效果时如果被嘲讽,相当于无法行动
+ GameWorld.DebugLog("行动时无法释放该技能! skillID=%s" % skillID)
+ continue
useCnt = curBatObj.GetSkillUseCnt(skillID)
useSkillList.append([useCnt, skillID, useSkill])
@@ -1452,6 +1679,14 @@
return True
def SetObjKilled(turnFight, gameObj, killer=None, useSkill=None):
+ curPlayer = turnFight.curPlayer
+ npcID = gameObj.GetNPCID()
+
+ # 非主线的PVE目标怪物
+ if npcID and curPlayer and turnFight.isFBMap() and gameObj.GetFaction() != ChConfig.Def_FactionA:
+ if not FBLogic.OnFBNPCKilledBefore(curPlayer, turnFight, gameObj, killer, useSkill):
+ return
+
objID = gameObj.GetID()
killerObjID = killer.GetID() if killer else 0
skillID = useSkill.GetSkillID() if useSkill else 0
@@ -1464,10 +1699,10 @@
clientPack.SkillID = skillID
turnFight.addBatPack(clientPack)
- curPlayer = turnFight.curPlayer
# 暂时只算主线小怪
if curPlayer and turnFight.mapID == ChConfig.Def_FBMapID_Main and gameObj.GetFaction() != ChConfig.Def_FactionA:
- PlayerTask.AddTaskValue(curPlayer, ChConfig.TaskType_KillNPC, 1)
+ PlayerTask.AddTaskValue(curPlayer, ChConfig.TaskType_KillNPC, 1)
+ PlayerActivity.AddDailyTaskValue(curPlayer, ChConfig.DailyTask_KillNPC, 1)
return True
def OnTurnAllOver(guid):
@@ -1499,6 +1734,7 @@
turnFight.costTime = time.time() - turnFight.startTime
winFaction = turnFight.winFaction
+ turnFight.isWin = (winFaction == ChConfig.Def_FactionA)
GameWorld.DebugLog("--- 战斗结束处理 ---, winFaction=%s, costTime=%ss, %s" % (winFaction, turnFight.costTime, guid))
# 统计明细
@@ -1509,11 +1745,13 @@
statInfo[str(faction)] = {}
facStatInfo = statInfo[str(faction)]
batFaction = turnFight.getBatFaction(faction)
+ batFaction.totalHurt = 0
for num in batFaction.lineupDict.keys():
if str(num) not in facStatInfo:
facStatInfo[str(num)] = {}
lineupStatInfo = facStatInfo[str(num)]
batLineup = batFaction.getBatlineup(num)
+ batLineup.totalHurt = 0
GameWorld.DebugLog("阵容明细: faction=%s,num=%s" % (faction, num))
for posNum, objID in batLineup.posObjIDDict.items():
batObj = batObjMgr.getBatObj(objID)
@@ -1525,132 +1763,21 @@
atkHurt = batObj.hurtStat
defHurt = batObj.defStat
cureHP = batObj.cureStat
+ batLineup.totalHurt += atkHurt
+ batFaction.totalHurt += atkHurt
GameWorld.DebugLog(" Pos:%s ID=%s,npcID=%s,heroID=%s,HP=%s/%s, 输出=%s,承伤=%s,治疗=%s"
% (posNum, objID, npcID, heroID, batObj.GetHP(), batObj.GetMaxHP(), atkHurt, defHurt, cureHP))
lineupStatInfo[str(posNum)] = {"ObjID":objID, "HeroID":heroID, "NPCID":npcID, "AtkHurt":atkHurt, "DefHurt":defHurt, "CureHP":cureHP}
- awardItemList = []
- playerID = turnFight.playerID
- if playerID:
- curPlayer = turnFight.curPlayer
- isWin = (winFaction == ChConfig.Def_FactionA)
- # 主线小怪
- if turnFight.mapID == ChConfig.Def_FBMapID_Main:
- OnOver_MainLevel(curPlayer, isWin, awardItemList)
- # 主线boss
- elif turnFight.mapID == ChConfig.Def_FBMapID_MainBoss:
- OnOver_MainLevelBoss(curPlayer, isWin, awardItemList)
- else:
- pass
-
- overMsg = {"winFaction":winFaction, "statInfo":statInfo, FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(awardItemList)}
+ overMsg = {"winFaction":winFaction, "statInfo":statInfo}
+ curPlayer = turnFight.curPlayer
+ mapID = turnFight.mapID
+ funcLineID = turnFight.funcLineID
+
+ FBLogic.OnTurnFightOver(curPlayer, turnFight, mapID, funcLineID, overMsg)
+
turnFight.syncState(FightState_Award, overMsg)
-
- # 除了主线外,其余战斗结束后均直接删除
- if not turnFight.playerID:
- tfMgr.delTurnFight(guid)
return
-
-def OnOver_MainLevel(curPlayer, isWin, awardItemList):
- ## 战斗结束额外处理 - 主线关卡
- if not curPlayer:
- return
- playerID = curPlayer.GetPlayerID()
- mainFightMgr = GetMainFightMgr(curPlayer)
- mainFightMgr.nextTeam = False
- chapterID, levelNum, wave = PlayerControl.GetMainLevelNowInfo(curPlayer)
-
- if not isWin:
- nextWave = max(1, wave - 1)
- nowValue = PlayerControl.SetMainLevelNowInfo(curPlayer, chapterID, levelNum, nextWave)
- GameWorld.DebugLog("主线小怪战斗失败,降一波! chapterID=%s,levelNum=%s,wave=%s,nextWave=%s,nowValue=%s"
- % (chapterID, levelNum, wave, nextWave, nowValue), playerID)
- return
-
- if mainFightMgr.teamNum < mainFightMgr.teamMax:
- mainFightMgr.nextTeam = True
- GameWorld.DebugLog("主线小怪战斗胜利,下一小队! chapterID=%s,levelNum=%s,wave=%s,teamNum=%s/%s"
- % (chapterID, levelNum, wave, mainFightMgr.teamNum, mainFightMgr.teamMax), playerID)
- return
-
- # 获胜过波
- if wave < mainFightMgr.waveMax:
- nextWave = min(mainFightMgr.waveMax, wave + 1)
- nowValue = PlayerControl.SetMainLevelNowInfo(curPlayer, chapterID, levelNum, nextWave)
- GameWorld.DebugLog("主线小怪波战斗胜利,下一波! chapterID=%s,levelNum=%s,wave=%s,nextWave=%s,nowValue=%s"
- % (chapterID, levelNum, wave, nextWave, nowValue), playerID)
- else:
- GameWorld.DebugLog("主线小怪波战斗胜利,最后一波循环刷! chapterID=%s,levelNum=%s,wave=%s" % (chapterID, levelNum, wave), playerID)
-
- # 小怪可能会退波,所以只在有超过已过关卡进度时才更新值
- hisPassValue = PlayerControl.GetMainLevelPassValue(curPlayer)
- curPassValue = PlayerControl.ComMainLevelValue(chapterID, levelNum, wave)
- if curPassValue > hisPassValue:
- GameWorld.DebugLog("更新当前过关进度! curPassValue=%s,hisPassValue=%s" % (curPassValue, hisPassValue), playerID)
- PlayerControl.SetMainLevelPassValue(curPlayer, curPassValue)
- else:
- GameWorld.DebugLog("未超过当前过关进度,不更新! curPassValue=%s <= hisPassValue=%s" % (curPassValue, hisPassValue), playerID)
-
- return
-
-def OnOver_MainLevelBoss(curPlayer, isWin, awardItemList):
- ## 战斗结束额外处理 - 主线关卡boss
- if not curPlayer:
- return
- playerID = curPlayer.GetPlayerID()
- mainFightMgr = GetMainFightMgr(curPlayer)
- mainFightMgr.nextTeam = False
- chapterID, levelNum, _ = PlayerControl.GetMainLevelPassInfo(curPlayer)
- if not isWin:
- nowValue = PlayerControl.GetMainLevelNowValue(curPlayer)
- GameWorld.DebugLog("主线boss战斗失败!保持当前刷怪波进度不变! nowValue=%s" % nowValue, playerID)
- return
-
- if mainFightMgr.teamNum < mainFightMgr.teamMax:
- mainFightMgr.nextTeam = True
- GameWorld.DebugLog("主线boss小队战斗胜利,下一小队! chapterID=%s,levelNum=%s,teamNum=%s/%s"
- % (chapterID, levelNum, mainFightMgr.teamNum, mainFightMgr.teamMax), playerID)
- return
-
- isAllPass = False # 是否通关
- if IpyGameDataPY.GetIpyGameDataNotLog("MainLevel", chapterID, levelNum + 1):
- nextChapterID, nextLevelNum = chapterID, levelNum + 1
- GameWorld.DebugLog("主线boss波战斗胜利!下一关! chapterID=%s,levelNum=%s,nextLevelNum=%s"
- % (chapterID, levelNum, nextLevelNum), playerID)
- elif IpyGameDataPY.GetIpyGameDataNotLog("MainLevel", chapterID + 1, 1):
- nextChapterID, nextLevelNum = chapterID + 1, 1
- GameWorld.DebugLog("主线boss波战斗胜利!下一章! chapterID=%s,levelNum=%s,nextChapterID=%s,nextLevelNum=%s"
- % (chapterID, levelNum, nextChapterID, nextLevelNum), playerID)
- else:
- # 已通关的暂时先保持不变
- # 注意防范最后一关奖励重复获得
- nextChapterID, nextLevelNum = chapterID + 1, 1
- GameWorld.DebugLog("主线boss波战斗胜利!已通关! chapterID=%s,levelNum=%s,nextChapterID=%s,nextLevelNum=%s"
- % (chapterID, levelNum, nextChapterID, nextLevelNum), playerID)
- isAllPass = True
-
- updPassValue = PlayerControl.SetMainLevelPassInfo(curPlayer, nextChapterID, nextLevelNum, 0)
- if isAllPass:
- # 已通关的刷怪进度保持不变
- updNowValue = PlayerControl.GetMainLevelNowValue(curPlayer)
- GameWorld.DebugLog("已通关的刷怪进度保持不变: updNowValue=%s" % updNowValue, playerID)
- else:
- updNowValue = PlayerControl.SetMainLevelNowInfo(curPlayer, nextChapterID, nextLevelNum, 1)
- GameWorld.DebugLog("为通关的刷怪进度设置为下一关的第1波: updNowValue=%s" % updNowValue, playerID)
- GameWorld.DebugLog("updPassValue=%s,updNowValue=%s" % (updPassValue, updNowValue), playerID)
-
- # 发放过关奖励
- levelIpyData = IpyGameDataPY.GetIpyGameData("MainLevel", chapterID, levelNum)
- if not levelIpyData:
- return
- itemList = levelIpyData.GetAwardItemList()
- GameWorld.DebugLog("过关奖励: chapterID=%s,levelNum=%s,itemList=%s" % (chapterID, levelNum, itemList), playerID)
-
- ItemControler.GivePlayerItemOrMail(curPlayer, itemList, event=["MainLevelBoss", False, {}], isNotifyAward=False)
-
- awardItemList += itemList
- return
-
#// B4 14 查看战报 #tagCSTurnFightReportView
#
@@ -1660,4 +1787,27 @@
# char GUID[40]; //战报guid
#};
def OnTurnFightReportView(index, clientData, tick):
+ curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+ guid = clientData.GUID
+
+ lastBatBufferInfo = PlayerOnline.GetOnlinePlayer(curPlayer).GetLastBatBuffer()
+ if lastBatBufferInfo and len(lastBatBufferInfo) == 2 and guid == lastBatBufferInfo[0]:
+ guid, reprot = lastBatBufferInfo
+ SyncTurnFightReport(curPlayer, guid, reprot)
+ return
+
+ # 其他战报,一般是入库存储的,待扩展
+
+ # 战报已过期
+ PlayerControl.NotifyCode(curPlayer, "FightReportExpired")
return
+
+def SyncTurnFightReport(curPlayer, guid, reprot):
+ ## 通知完整战报
+ clientPack = ChPyNetSendPack.tagSCTurnFightReport()
+ clientPack.GUID = guid
+ clientPack.Report = reprot
+ clientPack.Len = len(clientPack.Report)
+ NetPackCommon.SendFakePack(curPlayer, clientPack)
+ return
+
--
Gitblit v1.8.0