From 97fef842ed56dfd7c7dd73f9c7acf20df55b9a23 Mon Sep 17 00:00:00 2001 From: hxp <ale99527@vip.qq.com> Date: 星期五, 05 九月 2025 11:35:20 +0800 Subject: [PATCH] 129 【战斗】战斗系统-服务端(优化主线掉落装备:改为按Boss类型掉落,祝福树区分不同的Boss类型掉落概率;分解装备按消耗的战锤进行均分计算分解所得;) --- ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py | 1046 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 772 insertions(+), 274 deletions(-) diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py index b41a26b..e9f1b23 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py @@ -24,6 +24,7 @@ import ChPyNetSendPack import PlayerControl import ShareDefine +import TurnPassive import TurnAttack import TurnBuff import ObjPool @@ -44,11 +45,11 @@ ## 是否无视防御 return useSkill.GetHurtType() / 10 == 1 # 2为真伤,待扩展 -def OnUseSkill(turnFight, curBatObj, useSkill, tagObjList=None, batType=ChConfig.TurnBattleType_Normal, bySkill=None, isEnhanceSkill=False): +def OnUseSkill(turnFight, curBatObj, useSkill, tagObjList=None, batType=ChConfig.TurnBattleType_Normal, bySkill=None): '''使用技能通用入口 @param useSkill: 使用的技能,注意并不一定是身上的技能,可能只是 SkillData 表数据 @param bySkill: 由哪个技能额外触发的,比如附加触发的技能或被动技能均可能由某个技能触发 - @param isEnhanceSkill: 是否附加触发的技能,即主技能的EnhanceSkillList字段中的技能 + @param isEnhanceSkill: 是否附加触发的技能,即主技能拆分成多个技能,额外释放的 @return: 是否成功 ''' if not useSkill: @@ -65,14 +66,19 @@ tagAffect = useSkill.GetTagAffect() tagCount = useSkill.GetTagCount() tagObjList = GetSkillTags(turnFight, curBatObj, tagAim, tagFriendly, tagAffect, tagCount) - - bySkillID = bySkill.GetSkillID() if bySkill else 0 - GameWorld.DebugLog("使用技能: curID=%s,skillID=%s,tagCnt=%s,batType=%s,bySkillID=%s,isEnhanceSkill=%s" - % (curBatObj.GetID(), skillID, len(tagObjList), batType, bySkillID, isEnhanceSkill)) + rate = useSkill.GetHappenRate() + if rate and rate != ChConfig.Def_MaxRateValue: + for tagObj in tagObjList[::-1]: + if not GameWorld.CanHappen(rate, ChConfig.Def_MaxRateValue): + tagObjList.remove(tagObj) + if not tagObjList: # 可扩展其他目标选择,如复活技能没有死亡单位时则使用另外的效果 return + bySkillID = bySkill.GetSkillID() if bySkill else 0 + GameWorld.DebugLog("使用技能: curID=%s,skillID=%s,tagCnt=%s,batType=%s,bySkillID=%s" + % (curBatObj.GetID(), skillID, len(tagObjList), batType, bySkillID)) # 以下为技能可以使用的处理,之后的逻辑默认技能使用成功 poolMgr = ObjPool.GetPoolMgr() @@ -82,11 +88,10 @@ # 统一使用 BattleObj.PySkill useSkill = poolMgr.acquire(BattleObj.PySkill, useSkill) + useSkill.ResetUseRec() useSkill.SetTagObjList(tagObjList) useSkill.SetBatType(batType) useSkill.SetBySkill(bySkill) - useSkill.SetIsEnhanceSkill(isEnhanceSkill) - useSkill.ClearHurtObj() curBatObj.ClearSkillTempAttr() for tagObj in tagObjList: @@ -94,21 +99,25 @@ objID = curBatObj.GetID() useTag = "" - if not isEnhanceSkill: - # 因为可能触发连击,所以标记需带上累计使用技能次数,确保唯一 - useTag = "Skill_%s_%s_%s" % (objID, skillID, curBatObj.GetSkillUseCnt(skillID) + 1) - clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCTurnFightTag) - clientPack.Tag = useTag - clientPack.Len = len(clientPack.Tag) - clientPack.Sign = 0 - turnFight.addBatPack(clientPack) - + #这个技能是Buff if SkillCommon.IsBuff(useSkill): __doAddBuff(turnFight, curBatObj, useSkill) else: + # 主技能额外触发的技能可不下发,前端视为仅释放一个主技能 + if batType != ChConfig.TurnBattleType_Enhance: + # 因为可能触发连击,所以标记需带上累计使用技能次数,确保唯一 + useTag = "Skill_%s_%s_%s" % (objID, skillID, curBatObj.GetSkillUseCnt(skillID) + 1) + clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCTurnFightTag) + clientPack.Tag = useTag + clientPack.Len = len(clientPack.Tag) + clientPack.Sign = 0 + turnFight.addBatPack(clientPack) + __doUseSkill(turnFight, curBatObj, useSkill) + DoAttackResult(turnFight, curBatObj, useSkill) + if useTag: clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCTurnFightTag) clientPack.Tag = useTag @@ -116,28 +125,38 @@ clientPack.Sign = 1 turnFight.addBatPack(clientPack) + # 处理反击 或 连击 + DoCombo(turnFight, curBatObj, useSkill) + # 最后重置、回收对象 - useSkill.SetTagObjList([]) - useSkill.SetBySkill(None) # 需重置,防止被误回收 - useSkill.SetIsEnhanceSkill(False) - useSkill.ClearHurtObj() + useSkill.ResetUseRec() if usePoolSkill: poolMgr.release(useSkill) return True def GetSkillTags(turnFight, curBatObj, tagAim, tagFriendly, tagAffect, tagCount): - ## 获取技能目标 + ## 获取技能目标 + # @return: [主目标, 目标2, ...] + curFaction = curBatObj.GetFaction() # 自己,直接返回 if tagAim == ChConfig.SkillTagAim_Self: return [curBatObj] + sneerObj = None # 嘲讽目标 + sneerObjID, sneerObjPosNum = 0, 0 if tagFriendly: tagFaction = curFaction else: tagFaction = ChConfig.Def_FactionB if curFaction == ChConfig.Def_FactionA else ChConfig.Def_FactionA - + sneerObj = curBatObj.GetSneerTagObj() # 被嘲讽的目标,对敌的强制锁定被嘲讽目标 + + sneerObjFirst = True # 嘲讽目标优先 + if sneerObj: + sneerObjID = sneerObj.GetID() + sneerObjPosNum = sneerObj.GetPosNum() + batObjMgr = BattleObj.GetBatObjMgr() lineupNum = curBatObj.GetLineupNum() posNum = curBatObj.GetPosNum() @@ -157,123 +176,224 @@ # 对位 if tagAim == ChConfig.SkillTagAim_Relative: - posNumList = [posNum] # 优先对位位置,再其他位置按顺序遍历 - pNumList = batLineup.posObjIDDict.keys() - pNumList.sort() - for pNum in pNumList: - if pNum > 0 and pNum not in posNumList: - posNumList.append(pNum) - for pNum in posNumList: - if pNum not in batLineup.posObjIDDict: - continue - tagObjID = batLineup.posObjIDDict[pNum] - tagBatObj = batObjMgr.getBatObj(tagObjID) - if not __skillTagFilter(tagBatObj, tagAffect): - continue - aimObjList.append(tagBatObj) # 对位的默认只选1个 - break - + if sneerObj: + aimObjList.append(sneerObj) + else: + relativeObj = __GetRelativeObjDefault(batObjMgr, curBatObj, posNum, batLineup) + if relativeObj: + aimObjList.append(relativeObj) + # 前排 elif tagAim == ChConfig.SkillTagAim_FrontRow: - # 优先前排,如果没有则后排亦是前排 - for pNumList in [[1, 2, 3], [4, 5, 6]]: - hasObj = False - for pNum in pNumList: - if pNum not in batLineup.posObjIDDict: - continue - tagObjID = batLineup.posObjIDDict[pNum] - tagBatObj = batObjMgr.getBatObj(tagObjID) - if not __skillTagFilter(tagBatObj, tagAffect): - continue - hasObj = True - aimObjList.append(tagBatObj) - if hasObj: - break - + aimObjList = __getRowAimObjList(batObjMgr, posNum, sneerObj, batLineup, tagAffect, False) + # 后排 elif tagAim == ChConfig.SkillTagAim_BackRow: - # 优先后排,如果没有则前排亦是后排 - for pNumList in [[4, 5, 6], [1, 2, 3]]: - hasObj = False - for pNum in pNumList: - if pNum not in batLineup.posObjIDDict: - continue - tagObjID = batLineup.posObjIDDict[pNum] - tagBatObj = batObjMgr.getBatObj(tagObjID) - if not __skillTagFilter(tagBatObj, tagAffect): - continue - hasObj = True - aimObjList.append(tagBatObj) - if hasObj: - break - + aimObjList = __getRowAimObjList(batObjMgr, posNum, sneerObj, batLineup, tagAffect, True) + # 竖排/纵排 elif tagAim == ChConfig.SkillTagAim_Vertical: - verticalNumList = [[1, 4], [2, 5], [3, 6]] - for pNumList in verticalNumList: - # 优先对位排 - if posNum in pNumList: - verticalNumList.remove(pNumList) - verticalNumList.insert(0, pNumList) - break - for pNumList in verticalNumList: - hasObj = False - for pNum in pNumList: + # 优先自己所在纵 + inColNum = ChConfig.GetInColNum(posNum) + colNumList = range(1, 1 + ChConfig.TurnFightCols) + if inColNum in colNumList: + colNumList.remove(inColNum) + colNumList.insert(0, inColNum) + + # 优先嘲讽所在纵 + if sneerObj: + sneerInColNum = ChConfig.GetInColNum(sneerObjPosNum) + if sneerInColNum in colNumList: + colNumList.remove(sneerInColNum) + colNumList.insert(0, sneerInColNum) + + GameWorld.DebugLog("纵排: colNumList=%s,sneerObjID-PosNum=%s-%s" % (colNumList, sneerObjID, sneerObjPosNum)) + for col in colNumList: + for row in range(1, 1 + ChConfig.TurnFightRows): + pNum = (row - 1) * ChConfig.TurnFightCols + col + #GameWorld.DebugLog(" col=%s,row=%s,pNum=%s" % (col, row, pNum)) if pNum not in batLineup.posObjIDDict: continue tagObjID = batLineup.posObjIDDict[pNum] tagBatObj = batObjMgr.getBatObj(tagObjID) if not __skillTagFilter(tagBatObj, tagAffect): continue - hasObj = True aimObjList.append(tagBatObj) - if hasObj: + if aimObjList: break # 其他,默认全部 else: - pNumList = batLineup.posObjIDDict.keys() - for pNum in pNumList: - if pNum <= 0: - continue - tagObjID = batLineup.posObjIDDict[pNum] - tagBatObj = batObjMgr.getBatObj(tagObjID) - if not __skillTagFilter(tagBatObj, tagAffect): - continue - aimObjList.append(tagBatObj) + inColNum = ChConfig.GetInColNum(posNum) # 玩家所在纵列 + # 优先自己所在纵 + colNumList = range(1, 1 + ChConfig.TurnFightCols) + if inColNum in colNumList: + colNumList.remove(inColNum) + colNumList.insert(0, inColNum) + GameWorld.DebugLog("全部: colNumList=%s,sneerObjID-PosNum=%s-%s" % (colNumList, sneerObjID, sneerObjPosNum)) + # 按前排优先原则 + for row in range(1, 1 + ChConfig.TurnFightRows): + for col in colNumList: + pNum = (row - 1) * ChConfig.TurnFightCols + col + #GameWorld.DebugLog(" col=%s,row=%s,pNum=%s" % (col, row, pNum)) + if pNum not in batLineup.posObjIDDict: + continue + tagObjID = batLineup.posObjIDDict[pNum] + tagBatObj = batObjMgr.getBatObj(tagObjID) + if not __skillTagFilter(tagBatObj, tagAffect): + continue + aimObjList.append(tagBatObj) + # 目标细分 # 血量最低 if tagAffect == ChConfig.SkillTagAffect_HPLowest: aimObjList.sort(key=lambda o:(o.GetHP()), reverse=False) #GameWorld.DebugLog("血量最低排序: %s" % [[o.GetID(), o.GetHP(), o.GetMaxHP()] for o in aimObjList]) - aimObjList = aimObjList[:tagCount] # 血量最高 elif tagAffect == ChConfig.SkillTagAffect_HPHighest: aimObjList.sort(key=lambda o:(o.GetHP()), reverse=True) #GameWorld.DebugLog("血量最高排序: %s" % [[o.GetID(), o.GetHP(), o.GetMaxHP()] for o in aimObjList]) - aimObjList = aimObjList[:tagCount] + + # 未被控制优先 + elif tagAffect == ChConfig.SkillTagAffect_UncontrolledPriority: + sneerObjFirst = False + aimObjList.sort(key=lambda o:(o.IsInControlled())) + GameWorld.DebugLog("未被控制优先: %s" % [[o.GetID(), o.IsInControlled()] for o in aimObjList]) else: # 范围目标超过个数,则随机取 if tagCount and len(aimObjList) > tagCount: random.shuffle(aimObjList) - aimObjList = aimObjList[:tagCount] + # 嘲讽优先 + if sneerObjFirst and sneerObj: + if sneerObj in aimObjList and aimObjList.index(sneerObj) != 0: + aimObjList.remove(sneerObj) + aimObjList.insert(0, sneerObj) + + if tagCount and len(aimObjList) > tagCount: + aimObjList = aimObjList[:tagCount] + return aimObjList + +def __getRowAimObjList(batObjMgr, posNum, sneerObj, batLineup, tagAffect, rowReverse): + ## 获取行排目标对象列表 + # @param rowReverse: 是否后排优先原则 + + # 前后排顺序 + if rowReverse: + rowNumList = range(1, 1 + ChConfig.TurnFightRows)[::-1] + else: + rowNumList = range(1, 1 + ChConfig.TurnFightRows) + + # 优先嘲讽对象所在行 + sneerObjID, sneerObjPosNum = 0, 0 + if sneerObj: + sneerObjID = sneerObj.GetID() + sneerObjPosNum = sneerObj.GetPosNum() + sneerInRowNum = ChConfig.GetInRowNum(sneerObjPosNum) # 所在行排 + if sneerInRowNum in rowNumList: + rowNumList.remove(sneerInRowNum) + rowNumList.insert(0, sneerInRowNum) + + inColNum = ChConfig.GetInColNum(posNum) # 玩家所在纵列 + # 优先自己所在纵,为主目标 + colNumList = range(1, 1 + ChConfig.TurnFightCols) + if inColNum in colNumList: + colNumList.remove(inColNum) + colNumList.insert(0, inColNum) + + GameWorld.DebugLog("前后排: rowNumList=%s,colNumList=%s,sneerObjID-PosNum=%s-%s" % (rowNumList, colNumList, sneerObjID, sneerObjPosNum)) + aimObjList = [] + for row in rowNumList: + for col in colNumList: + pNum = (row - 1) * ChConfig.TurnFightCols + col + #GameWorld.DebugLog(" row=%s,col=%s,pNum=%s" % (row, col, pNum)) + if pNum not in batLineup.posObjIDDict: + continue + tagObjID = batLineup.posObjIDDict[pNum] + tagBatObj = batObjMgr.getBatObj(tagObjID) + if not __skillTagFilter(tagBatObj, tagAffect): + continue + aimObjList.append(tagBatObj) + if aimObjList: + break + + return aimObjList + +def GetRelativeObj(turnFight, curBatObj): + '''获取对位目标,嘲讽时优先对位嘲讽目标 + 对位目标用途: + 1. 对位目标并不代表仅攻击该目标 + 2. 攻击时根据技能攻击目标范围优先攻击对位目标所在的横排或纵排 + 3. 对位目标可用于判断连击、弱疗 + ''' + sneerObj = curBatObj.GetSneerTagObj() + if sneerObj: + # 有嘲讽目标优先直接对位 + return sneerObj + + curFaction = curBatObj.GetFaction() + # 默认对位敌对阵营 + tagFaction = ChConfig.Def_FactionB if curFaction == ChConfig.Def_FactionA else ChConfig.Def_FactionA + + batObjMgr = BattleObj.GetBatObjMgr() + lineupNum = curBatObj.GetLineupNum() + posNum = curBatObj.GetPosNum() + + batFaction = turnFight.getBatFaction(tagFaction) + lineupNumList = [lineupNum] # 敌方优先对位阵容,再其他阵容,支持多阵容对战 + for tagNum in batFaction.lineupDict.keys(): + if tagNum not in lineupNumList: + lineupNumList.append(tagNum) + + for num in lineupNumList: + batLineup = batFaction.getBatlineup(num) + relativeObj = __GetRelativeObjDefault(batObjMgr, curBatObj, posNum, batLineup) + if relativeObj: + return relativeObj + + # 理论上只要战斗没有结束,一定会有对位目标,这里默认返回自己,外层可不需要判断是否存在对位目标 + return curBatObj + +def __GetRelativeObjDefault(batObjMgr, curBatObj, posNum, batLineup): + ## 获取在某一阵营中的默认对位目标 + + tagAffect = ChConfig.SkillTagAffect_None # 默认对位目标不需要细分目标,默认规则即可 + inColNum = ChConfig.GetInColNum(posNum) # 玩家所在纵列 + # 优先自己所在纵 + colNumList = range(1, 1 + ChConfig.TurnFightCols) + if inColNum in colNumList: + colNumList.remove(inColNum) + colNumList.insert(0, inColNum) + + # 按前排优先原则 + for row in range(ChConfig.TurnFightRows): + for col in colNumList: + pNum = row * ChConfig.TurnFightCols + col + if pNum not in batLineup.posObjIDDict: + continue + tagObjID = batLineup.posObjIDDict[pNum] + tagBatObj = batObjMgr.getBatObj(tagObjID) + if not __skillTagFilter(tagBatObj, tagAffect): + continue + return tagBatObj + + return def __skillTagFilter(tagBatObj, tagAffect): ## 技能目标过滤器 # @return: 是否允许添加该单位 if not tagBatObj: return False - if tagAffect != ChConfig.SkillTagAffect_Death and tagBatObj.GetHP() <= 0: + if tagAffect != ChConfig.SkillTagAffect_Death and not tagBatObj.IsAlive(): return False - if tagAffect == ChConfig.SkillTagAffect_Death and tagBatObj.GetHP() > 0: + if tagAffect == ChConfig.SkillTagAffect_Death and tagBatObj.IsAlive(): return False - if not tagBatObj.GetCanAttack(): - return False + #if not tagBatObj.GetCanAttack(): 策划要求不可攻击的对象也要可选中 + # return False return True def __doAddBuff(turnFight, curBatObj, useSkill): @@ -282,7 +402,6 @@ for tagBatObj in useSkill.GetTagObjList(): TurnBuff.OnAddBuff(turnFight, tagBatObj, useSkill, buffOwner=curBatObj) - DoAttackResult(turnFight, curBatObj, useSkill) return def __doUseSkill(turnFight, curBatObj, useSkill): @@ -292,40 +411,36 @@ # 通用攻击 if atkType == 1: SkillModule_1(turnFight, curBatObj, useSkill) - return - # 治疗 if atkType == 2: SkillModule_2(turnFight, curBatObj, useSkill) - return - # 复活 - if atkType == 3: - return - + elif atkType == 3: + pass # 多次攻击(锁目标多次伤害,非前端的多段飘血) - if atkType == 4: - return - + elif atkType == 4: + pass # 弹射(多次攻击,切换目标) - if atkType == 5: - return - - # 6 怒气增减偷 - if atkType == 6: - SkillModule_6(turnFight, curBatObj, useSkill) - return - + elif atkType == 5: + pass + # 怒气增 + elif atkType == 6: + SkillModule_6(turnFight, curBatObj, useSkill, "Increase") + # 怒气减 + elif atkType == 7: + SkillModule_6(turnFight, curBatObj, useSkill, "Reduce") + # 怒气偷 + elif atkType == 8: + SkillModule_6(turnFight, curBatObj, useSkill, "Steal") + return def SkillModule_1(turnFight, curBatObj, useSkill): ## 通用攻击,单攻、群攻 - #执行攻击结果 for tagBatObj in useSkill.GetTagObjList(): - __doSkillHurtHP(curBatObj, tagBatObj, useSkill) + __doSkillHurtHP(turnFight, curBatObj, tagBatObj, useSkill) - DoAttackResult(turnFight, curBatObj, useSkill) return def SkillModule_2(turnFight, curBatObj, useSkill): @@ -354,10 +469,9 @@ TurnAttack.AddTurnObjCureHP(tagBatObj, curBatObj, cureHP, realCureHP, skillID) - DoAttackResult(turnFight, curBatObj, useSkill) return -def SkillModule_6(turnFight, curBatObj, useSkill): +def SkillModule_6(turnFight, curBatObj, useSkill, opType): ## 怒气增减偷 curID = curBatObj.GetID() @@ -365,24 +479,22 @@ bySkill = useSkill.GetBySkill() relatedSkillID = bySkill.GetSkillID() if bySkill else 0 - angerPer, angerValue, calcType = 0, 0, 0 - effect = SkillCommon.GetSkillEffectByEffectID(useSkill, ChConfig.Def_Skill_Effect_Anger) - if effect: - angerPer = effect.GetEffectValue(0) - angerValue = effect.GetEffectValue(1) - calcType = effect.GetEffectValue(2) + #cureType = useSkill.GetCalcType() + skillPer = useSkill.GetSkillPer() + skillValue = useSkill.GetSkillValue() + xpMax = IpyGameDataPY.GetFuncCfg("AngerXP", 2) - calcValue = int(xpMax * angerPer / 10000.0 + angerValue) + calcValue = int(xpMax * skillPer / 10000.0 + skillValue) attrID = ChConfig.AttrID_XP - GameWorld.DebugLog("怒气增减偷: curID=%s,calcValue=%s,skillID=%s,angerPer=%s,angerValue=%s,calcType=%s,relatedSkillID=%s" - % (curID, calcValue, skillID, angerPer, angerValue, calcType, relatedSkillID)) + GameWorld.DebugLog("怒气%s: curID=%s,calcValue=%s,skillID=%s,skillPer=%s,skillValue=%s,relatedSkillID=%s" + % (opType, curID, calcValue, skillID, skillPer, skillValue, relatedSkillID)) curStealTotal = 0 for tagBatObj in useSkill.GetTagObjList(): tagID = tagBatObj.GetID() # 减 - if calcType == 2: + if opType == "Reduce": diffType = 0 tagXP = tagBatObj.GetXP() diffValue = min(tagXP, calcValue) # 取较小值,不足时剩多少减多少 @@ -392,7 +504,7 @@ Sync_PropertyRefreshView(turnFight, tagBatObj, attrID, updValue, diffValue, diffType, skillID, relatedSkillID) # 偷 - elif calcType == 3: + elif opType == "Steal": diffType = 0 tagXP = tagBatObj.GetXP() diffValue = min(tagXP, calcValue) # 取较小值,不足时剩多少减多少 @@ -419,14 +531,13 @@ diffValue = curStealTotal updValue = curXP + diffValue curBatObj.SetXP(updValue, False) - GameWorld.DebugLog(" 偷总怒气: curID=%s,curStealTotal=%s,curXP=%s,updXP=%s" % (curID, curStealTotal, curXP, updValue)) + GameWorld.DebugLog(" 加总怒气: curID=%s,curStealTotal=%s,curXP=%s,updXP=%s" % (curID, curStealTotal, curXP, updValue)) Sync_PropertyRefreshView(turnFight, curBatObj, attrID, updValue, diffValue, diffType, skillID, relatedSkillID) - DoAttackResult(turnFight, curBatObj, useSkill) return def DoAttackResult(turnFight, curBatObj, useSkill): - '''执行攻击结果,技能、buff通用 + '''执行攻击结果 @param curBatObj: 施法方或buff归属方 ''' @@ -437,41 +548,199 @@ skillID = useSkill.GetSkillID() curBatObj.AddSkillUseCnt(skillID) - - # 需先通知伤血 - 前端按顺序优先表现技能释放内容, - isEnhanceSkill = useSkill.GetIsEnhanceSkill() - if not isEnhanceSkill or len(useSkill.GetHurtObjList()): - Sync_UseSkill(turnFight, curBatObj, useSkill) - if not isEnhanceSkill: - __doCostZhanchui(turnFight, curBatObj, useSkill) - __doSkillUserAnger(turnFight, curBatObj, useSkill) + if useSkill.GetCoolDownTime(): + useSkill.SetCalcTime(turnFight.getTimeline()) + useSkill.SetRemainTime(useSkill.GetCoolDownTime()) - # 统计死亡 - killObjIDList = [] # 击杀的目标ID列表 + # 需先技能使用 - 前端按顺序优先表现技能释放内容,前端需要动作或有伤血则通知 + if useSkill.GetSkillMotionName() or len(useSkill.GetHurtObjList()): + Sync_UseSkill(turnFight, curBatObj, useSkill) + + __doCostZhanchui(turnFight, curBatObj, useSkill) + __doSkillUserAnger(turnFight, curBatObj, useSkill) + + DoBeAttackResult(turnFight, curBatObj, useSkill, True) + return + +def DoCombo(turnFight, curBatObj, useSkill): + ''' + 格挡、反击、连击规则 + 1. 所有武将或怪物均可能产生格挡,群攻时格挡一对一判断,均可能产生格挡 + 2. 仅普攻时可被反击,反判断本次技能目标中的主目标(即对位目标)是否产生格挡,且是近战武将,是的话可反击 + + 连击: + 1. 仅普攻可连击,反击打断连击 + 2. 非对敌技能,如奶妈回血普攻,判断对位目标抗连属性是否可连击 + 3. 对敌技能,判断本次技能目标中的主目标(即对位目标)抗连属性是否可连击 + + 对敌技能主目标: + 单体: 默认该目标 + 嘲讽: 优先被嘲讽的目标 + 横排: 优先该排中与自己同列的,否则按顺序 + 纵排: 优先前面的单位 + ''' + + if not SkillCommon.isTurnNormalSkill(useSkill): + #GameWorld.DebugLog("非普攻不处理反击连击") + return + + tagFriendly = useSkill.GetTagFriendly() + if tagFriendly: + tagObj = GetRelativeObj(turnFight, curBatObj) + else: + tagObjList = useSkill.GetTagObjList() + if not tagObjList: + return + tagObj = tagObjList[0] # 第一个默认为主目标,技能对象选择逻辑时决定主目标 + atkBackSkill = __getCanAtkBackSkill(useSkill, tagObj) + if atkBackSkill: + # 可以反击,打断连击 + GameWorld.DebugLog("● %s 【反击】" % TurnAttack.GetObjName(tagObj)) + OnUseSkill(turnFight, tagObj, atkBackSkill, [curBatObj], ChConfig.TurnBattleType_AtkBack) + return + + if not tagObj: + return + + if CanCombo(curBatObj, tagObj): + # 连击根据技能目标配置逻辑重新选择目标 + GameWorld.DebugLog("● %s 【连击】" % TurnAttack.GetObjName(curBatObj)) + OnUseSkill(turnFight, curBatObj, useSkill, batType=ChConfig.TurnBattleType_Combo) + + return + +def __getCanAtkBackSkill(useSkill, tagObj): + ## 获取是否可反击及反击技能 + if not tagObj: + return + + tagID = tagObj.GetID() + if tagObj.GetAtkDistType() != ChConfig.AtkDistType_Short: + GameWorld.DebugLog("非近战不可反击! tagID=%s" % tagID) + return + + canAtkBack = False + for hurtObj in useSkill.GetHurtObjList(): + if hurtObj.GetObjID() != tagID: + continue + if hurtObj.HaveHurtType(ChConfig.HurtType_Parry): # 格挡时可反击 + canAtkBack = True + break + + if not canAtkBack: + GameWorld.DebugLog("没有格挡不可反击! tagID=%s" % tagID) + return + + skillManager = tagObj.GetSkillManager() + for index in range(0, skillManager.GetSkillCount()): + useSkill = skillManager.GetSkillByIndex(index) + if not useSkill: + continue + if useSkill.GetFuncType() == ChConfig.Def_SkillFuncType_AtkbackSkill: + GameWorld.DebugLog("可以反击! tagID=%s" % tagID) + return useSkill + return + +def CanCombo(atkObj, defObj): + ## 可否连击 + comboNum = atkObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnComboNum) + aComboRate = atkObj.GetBatAttrValue(ChConfig.AttrID_ComboRate) + dComboRateDef = defObj.GetBatAttrValue(ChConfig.AttrID_ComboRateDef) + happenRate = eval(IpyGameDataPY.GetFuncCompileCfg("ComboCfg", 1)) + if GameWorld.CanHappen(happenRate): + GameWorld.DebugLog("可以连击! atkID=%s,happenRate=%s,aComboRate=%s,dComboRateDef=%s,comboNum=%s" + % (atkObj.GetID(), happenRate, aComboRate, dComboRateDef, comboNum)) + atkObj.SetDict(ChConfig.Def_Obj_Dict_TurnComboNum, comboNum + 1) + return True + GameWorld.DebugLog("无法连击! atkID=%s,happenRate=%s,aComboRate=%s,dComboRateDef=%s,comboNum=%s" + % (atkObj.GetID(), happenRate, aComboRate, dComboRateDef, comboNum)) + return False + +def DoBeAttackResult(turnFight, curObj, useSkill, isUseSkill=False): + '''被攻击结果 + @param curObj: 施法方或buff归属方 + @param isUseSkill: 是否是直接使用技能的攻击结果 + ''' + + curID = curObj.GetID() + isTurnNormalSkill = SkillCommon.isTurnNormalSkill(useSkill) + isAngerSkill = SkillCommon.isAngerSkill(useSkill) + + batObjMgr = BattleObj.GetBatObjMgr() + + # 优先处理afterLogic,可再预先汇总一些会触发被动的信息 + relatedSkillID = useSkill.GetSkillID() + shieldBrokenList = [] # 记录盾破 + afterLogicList = useSkill.GetAfterLogicList() + for logicType, logicData in afterLogicList: + if logicType == ChConfig.AfterLogic_DelBuff: + buffObjID, buff, tagObjID = logicData + buffSkillData = buff.GetSkillData() + buffSkillTypeID = buffSkillData.GetSkillTypeID() + TurnBuff.DoBuffDelAfterLogicOver(turnFight, buffObjID, buff, useSkill) + if SkillCommon.isDamageShieldSkill(buffSkillData): + shieldBrokenList.append([buffObjID, tagObjID, buffSkillTypeID]) + + elif logicType == ChConfig.AfterLogic_AddBuff: + batObj = logicData[0] + buff = logicData[1] + TurnBuff.SyncBuffRefresh(turnFight, batObj, buff, relatedSkillID, isNewAdd=True) + + elif logicType == ChConfig.AfterLogic_SyncBuff: + buffObj = logicData[0] + buff = logicData[1] + TurnBuff.SyncBuffRefresh(turnFight, buffObj, buff, relatedSkillID) + + # 统计击杀 + killObjList = [] # 击杀其他阵营目标列表 for tagObj in useSkill.GetTagObjList(): tagID = tagObj.GetID() - # 可能单个技能对同一目标造成多次伤害,所以这里遍历,如弹射等 - for hurtObj in useSkill.GetHurtObjList(): - if hurtObj.GetObjID() == tagID and not hurtObj.HaveHurtType(ChConfig.HurtTYpe_Recovery): - __doSkillHurtAnger(tagObj, hurtObj.GetLostHP(), useSkill) - if tagObj.GetHP() <= 0: - killObjIDList.append(tagID) - TurnAttack.SetObjKilled(turnFight, tagObj, curBatObj, useSkill) - if curBatObj.GetHP() <= 0: - TurnAttack.SetObjKilled(turnFight, curBatObj) + if tagObj.IsAlive() and tagObj.GetHP() <= 0 and tagObj.GetFaction() != curObj.GetFaction(): + killObjList.append(tagObj) + TurnAttack.SetObjKilled(turnFight, tagObj, curObj, useSkill) + if curObj.IsAlive() and curObj.GetHP() <= 0: + TurnAttack.SetObjKilled(turnFight, curObj) + # 统计伤血,可能单个技能对同一目标造成多次伤害 + missObjIDList = [] + for hurtObj in useSkill.GetHurtObjList(): + hurtObjID = hurtObj.GetObjID() + tagObj = batObjMgr.getBatObj(hurtObjID) + if not tagObj: + continue + if not hurtObj.HaveHurtType(ChConfig.HurtTYpe_Recovery) and (isTurnNormalSkill or isAngerSkill) and tagObj.IsAlive(): + __doSkillHurtAnger(tagObj, hurtObj.GetLostHP(), useSkill) + if hurtObj.HaveHurtType(ChConfig.HurtType_Miss): + missObjIDList.append(hurtObjID) + # 结算副本相关的攻击结果,仅主动发起玩家阵容武将触发 curPlayer = turnFight.curPlayer - if curPlayer and curBatObj.GetOwnerID() == curPlayer.GetPlayerID(): - FBLogic.OnPlayerLineupAttackResult(curPlayer, curBatObj, killObjIDList, useSkill, turnFight.mapID, turnFight.funcLineID) + if curPlayer and curObj and curObj.GetOwnerID() == curPlayer.GetPlayerID(): + FBLogic.OnPlayerLineupAttackResult(curPlayer, curObj, killObjList, useSkill, turnFight.mapID, turnFight.funcLineID) - # 额外触发技能 - __doUseEnhanceSkill(turnFight, curBatObj, useSkill) + # 优先触发本技能额外效果,注:仅该技能释放后该技能的额外效果视为主技能的效果,优先级最高 + if isUseSkill: + __DoCurSkillEff(turnFight, curObj, useSkill, missObjIDList) + + # ========== 以下触发被动 ========== - # 循环触发被动,待扩展 - - # 最后处理反击 或 连击 - + # 破盾时 + for buffObjID, tagObjID, buffSkillTypeID in shieldBrokenList: + buffObj = batObjMgr.getBatObj(buffObjID) + tagObj = batObjMgr.getBatObj(tagObjID) + TurnPassive.OnTriggerPassiveEffect(turnFight, buffObj, ChConfig.TriggerWay_ShieldBroken, tagObj, connSkillTypeID=buffSkillTypeID) + + for tagObj in useSkill.GetTagObjList(): + tagID = tagObj.GetID() + if tagID == curID or tagID in missObjIDList: + # 自己或对方闪避了不再触发被动 + continue + + # 直接攻击 + if isUseSkill and not SkillCommon.IsBuff(useSkill) and useSkill.GetSkillType() in [ChConfig.Def_SkillType_Atk]: + TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_AttackOverDirect, tagObj, connSkill=useSkill) + TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_BeAttackedDirect, curObj, connSkill=useSkill) + return def __doCostZhanchui(turnFight, curBatObj, useSkill): @@ -490,12 +759,12 @@ costZhanchui = 0 batType = useSkill.GetBatType() + if batType != ChConfig.TurnBattleType_Normal: + # 暂定仅常规主动点击行为的需要扣除战锤(与前端手动战斗点击的触发点同步),被动触发的暂定不扣 + return + if SkillCommon.isAngerSkill(useSkill): costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 2) - elif batType == ChConfig.TurnBattleType_Combo: - costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 3) - elif batType == ChConfig.TurnBattleType_AtkBack: - costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 4) elif SkillCommon.isTurnNormalSkill(useSkill): costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 1) @@ -545,81 +814,144 @@ GameWorld.DebugLog(" 更新XP: curID=%s,curXP=%s,addXP=%s,updXP=%s,reason=%s" % (gameObj.GetID(), curXP, addXP, updXP, reason)) return -def __doUseEnhanceSkill(turnFight, curBatObj, useSkill): - if useSkill.GetIsEnhanceSkill(): - GameWorld.DebugLog("自身为额外触发的技能不再触发额外技能! skillID=%s" % useSkill.GetSkillID()) - return - enhanceSkillIDList = useSkill.GetEnhanceSkillList() - if not enhanceSkillIDList: - return - GameWorld.DebugLog("额外触发的技能! skillID=%s,enhanceSkillIDList=%s" % (useSkill.GetSkillID(), enhanceSkillIDList)) - # 根据触发技能的特点决定是触发一次还是 触发多次 - # 群体BUFF的请参考 IsPlayerUseSkill 客户端决定对象,一样可以实现同样效果 - tagObjList = useSkill.GetTagObjList() - for enhanceSkillID in enhanceSkillIDList: - enhanceSkillData = IpyGameDataPY.GetIpyGameData("Skill", enhanceSkillID) - if not enhanceSkillData: - continue - # 继承主技能目标 - if enhanceSkillData.GetTagAim() == ChConfig.SkillTagAim_MainSkill: - GameWorld.DebugLog(" 额外触发技能,继承主技能目标! enhanceSkillID=%s" % enhanceSkillID) - # 额外触发的技能直接在外层检查概率,如果都没有触发则不需要再处理 - enhanceRate = enhanceSkillData.GetHappenRate() - enchanceTagObjList = [] - for tagObj in tagObjList: - tagID = tagObj.GetID() - if tagObj.GetHP() <= 0: - GameWorld.DebugLog(" 已被击杀不触发: tagID=%s" % (tagID)) - continue - inHurt = False - for hurtObj in useSkill.GetHurtObjList(): - if hurtObj.GetObjID() != tagID: - continue - if not hurtObj.GetHurtHP() or hurtObj.HaveHurtType(ChConfig.HurtType_Miss): - continue - inHurt = True - break - if not inHurt: - GameWorld.DebugLog(" 没有伤血不触发: tagID=%s" % (tagID)) - continue - if enhanceRate and enhanceRate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(enhanceRate, ChConfig.Def_MaxRateValue): - GameWorld.DebugLog(" 概率不触发: tagID=%s,enhanceRate=%s" % (tagID, enhanceRate)) - continue - - enchanceTagObjList.append(tagObj) - - if enchanceTagObjList: - OnUseSkill(turnFight, curBatObj, enhanceSkillData, enchanceTagObjList, bySkill=useSkill, isEnhanceSkill=True) - +def __DoCurSkillEff(turnFight, curObj, useSkill, missObjIDList): + ## 执行本技能/buff释放后额外效果 + for index in xrange(useSkill.GetEffectCount()): + curEffect = useSkill.GetEffect(index) + if curEffect.GetTriggerWay() != ChConfig.TriggerWay_CurSkillEff: continue - GameWorld.DebugLog(" 额外触发技能,重新锁定目标! enhanceSkillID=%s" % enhanceSkillID) - OnUseSkill(turnFight, curBatObj, enhanceSkillData, bySkill=useSkill, isEnhanceSkill=True) + effID = curEffect.GetEffectID() + GameWorld.DebugLog("执行额外技能效果: %s, missObjIDList=%s" % (effID, missObjIDList)) + if effID == 5010: + # 额外技能效果 + __doUseEnhanceSkill(turnFight, curObj, useSkill, curEffect, missObjIDList) + continue + for tagObj in useSkill.GetTagObjList(): + tagID = tagObj.GetID() + GameWorld.DebugLog(" tagID=%s" % (tagID)) + if tagID in missObjIDList: + # 闪避了不触发 + continue + + TurnPassive.DoSkillEffectLogic(turnFight, curObj, tagObj, useSkill, curEffect, useSkill) + return -def __doSkillHurtHP(attacker, defObj, curSkill): +def __doUseEnhanceSkill(turnFight, curBatObj, useSkill, curEffect, missObjIDList): + ## 执行主技能的额外技能效果 + #if useSkill.GetBatType() == ChConfig.TurnBattleType_Enhance: + # #GameWorld.DebugLog("自身为额外触发的技能不再触发额外技能! skillID=%s" % useSkill.GetSkillID()) + # return + enhanceSkillID = curEffect.GetEffectValue(0) + checkInStateList = curEffect.GetEffectValue(1) + if checkInStateList: + if isinstance(checkInStateList, int): + checkInStateList = [checkInStateList] + GameWorld.DebugLog("额外触发的技能: enhanceSkillID=%s,checkInStateList=%s" % (enhanceSkillID, checkInStateList)) + tagObjList = useSkill.GetTagObjList() + + enhanceSkillData = IpyGameDataPY.GetIpyGameData("Skill", enhanceSkillID) + if not enhanceSkillData: + return + + # 继承主技能目标 + if enhanceSkillData.GetTagAim() == ChConfig.SkillTagAim_MainSkill: + GameWorld.DebugLog("继承主技能目标! enhanceSkillID=%s" % enhanceSkillID) + # 额外触发的技能直接在外层检查概率,如果都没有触发则不需要再处理 + enhanceRate = enhanceSkillData.GetHappenRate() + enchanceTagObjList = [] + for tagObj in tagObjList: + tagID = tagObj.GetID() + if not tagObj.IsAlive(): + GameWorld.DebugLog(" 已被击杀不触发: tagID=%s" % (tagID)) + continue + if tagID in missObjIDList: + GameWorld.DebugLog(" 闪避的不触发: tagID=%s" % (tagID)) + continue + if checkInStateList: + inState = False + for state in checkInStateList: + if tagObj.IsInState(state): + inState = True + break + if not inState: + GameWorld.DebugLog(" 不在状态下不触发: tagID=%s not in state:%s" % (tagID, checkInStateList)) + continue + if enhanceRate and enhanceRate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(enhanceRate, ChConfig.Def_MaxRateValue): + GameWorld.DebugLog(" 概率不触发: tagID=%s,enhanceRate=%s" % (tagID, enhanceRate)) + continue + + enchanceTagObjList.append(tagObj) + + if enchanceTagObjList: + OnUseSkill(turnFight, curBatObj, enhanceSkillData, enchanceTagObjList, batType=ChConfig.TurnBattleType_Enhance, bySkill=useSkill) + + return + + # 只执行一次,防止群攻时额外触发多次 + GameWorld.DebugLog("重新锁定目标! enhanceSkillID=%s" % enhanceSkillID) + if checkInStateList: + inState = False + for tagObj in tagObjList: + for state in checkInStateList: + if not state or tagObj.IsInState(state): + inState = True + break + if inState: + break + if not inState: + GameWorld.DebugLog(" 没有目标在状态下不触发: tagObj not in state:%s" % str(checkInStateList)) + return + OnUseSkill(turnFight, curBatObj, enhanceSkillData, batType=ChConfig.TurnBattleType_Enhance, bySkill=useSkill) + return + +def OnUsePassiveSkill(turnFight, batObj, tagObj, passiveSkill, connSkill=None, effSkillID=0, effectID=0): + '''被动触发使用技能 + @param passiveSkill: 释放的被动技能 + @param connSkill: 由什么技能引起的 + @param effSkillID: 被动效果所属的技能ID + @param effectID: 被动效果ID + 注:可能由A引起触发B技能的效果释放技能C + ''' + if not passiveSkill: + return + isOK = False + passiveSkillID = passiveSkill.GetSkillID() + # 继承主技能目标 + if passiveSkill.GetTagAim() == ChConfig.SkillTagAim_MainSkill: + happenRate = passiveSkill.GetHappenRate() + GameWorld.DebugLog("被动触发技能,继承主技能目标! effSkillID=%s,effectID=%s,passiveSkillID=%s,happenRate=%s" % (effSkillID, effectID, passiveSkillID, happenRate)) + if not tagObj: + return + tagID = tagObj.GetID() + if not tagObj.IsAlive(): + GameWorld.DebugLog(" 已被击杀不触发: tagID=%s" % (tagID)) + return + if happenRate and happenRate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(happenRate, ChConfig.Def_MaxRateValue): + GameWorld.DebugLog(" 概率不触发: tagID=%s,happenRate=%s" % (tagID, happenRate)) + return + passiveTagObjList = [tagObj] + isOK = OnUseSkill(turnFight, batObj, passiveSkill, passiveTagObjList, batType=ChConfig.TurnBattleType_Passive, bySkill=connSkill) + else: + GameWorld.DebugLog("被动触发技能,重新锁定目标! effSkillID=%s,effectID=%s,passiveSkillID=%s" % (effSkillID, effectID, passiveSkillID)) + isOK = OnUseSkill(turnFight, batObj, passiveSkill, batType=ChConfig.TurnBattleType_Passive, bySkill=connSkill) + + return isOK + +def __doSkillHurtHP(turnFight, attacker, defObj, curSkill): ## 执行技能伤血,只计算伤血,其他逻辑等技能同步后再处理 # @return: None - 没有执行成功,即忽略该目标 atkObj = attacker atkID = atkObj.GetID() defID = defObj.GetID() + skillID = curSkill.GetSkillID() hurtObj = curSkill.AddHurtObj(defID) - #检查是否几率触发,附加技能、被动触发的外层已检查过概率,不重复检查 - if not (curSkill.GetIsEnhanceSkill() or SkillCommon.isPassiveTriggerSkill(curSkill)): # 额外触发的技能概率在触发时判断 - rate = curSkill.GetHappenRate() - if rate and rate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(rate, ChConfig.Def_MaxRateValue): - #GameWorld.Log('检查是否几率触发 = %s失败 = %s'%(rate, useSkill.GetSkillName())) - #放这里,兼容群攻时如果该技能是有概率的,则每个目标单独判断 - hurtObj.AddHurtType(ChConfig.HurtType_Fail) - hurtObj.SetCurHP(defObj.GetHP()) - return hurtObj - - effect = SkillCommon.GetSkillEffectByEffectID(curSkill, ChConfig.Def_Skill_Effect_Attack) - atkSkillValue = 0 - atkSkillPer = effect.GetEffectValue(0) if effect else 0 + atkSkillPer = curSkill.GetSkillPer() + atkSkillValue = curSkill.GetSkillValue() dHP = defObj.GetHP() # 防守方当前血量 dMaxHP = defObj.GetMaxHP() # 防守方最大血量 @@ -630,34 +962,33 @@ pass else: - hurtValue, hurtTypes = CalcHurtHP(atkObj, defObj, curSkill, atkSkillValue, atkSkillPer) - - # 各种减伤 吸收盾处理 - #hurtValue = CalcHurtHPWithBuff(atkObj, defObj, hurtValue, curSkill, tick) + hurtValue, hurtTypes = CalcHurtHP(turnFight, atkObj, defObj, curSkill, atkSkillValue, atkSkillPer) + hurtValue, realHurtHP = CalcHurtHPWithBuff(turnFight, atkObj, defObj, curSkill, hurtValue) #伤害结构体 hurtObj.SetHurtTypes(hurtTypes) hurtObj.SetHurtHP(hurtValue) - remainHP = min(dMaxHP, max(0, dHP - hurtValue)) # 剩余血量 + hurtObj.SetRealHurtHP(realHurtHP) + remainHP = min(dMaxHP, max(0, dHP - realHurtHP)) # 剩余血量 remainHP = int(remainHP) #防范 lostHP = dHP - remainHP # 实际掉血量 hurtObj.SetLostHP(lostHP) hurtObj.SetCurHP(remainHP) defObj.SetHP(remainHP) - GameWorld.DebugLog(" 伤血: atkID=%s,defID=%s,hurtValue=%s,lostHP=%s,%s/%s" % (atkID, defID, hurtValue, lostHP, defObj.GetHP(), defObj.GetMaxHP())) + GameWorld.DebugLog(" 伤血: atkID=%s,defID=%s,hurtValue=%s,realHurtHP=%s,lostHP=%s,%s/%s" + % (atkID, defID, hurtValue, realHurtHP, lostHP, defObj.GetHP(), defObj.GetMaxHP())) + TurnAttack.AddTurnObjHurtValue(atkObj, defObj, hurtValue, lostHP, skillID) #反弹伤害 - CalcBounceHP(atkObj, defObj, hurtObj, curSkill) + CalcBounceHP(turnFight, atkObj, defObj, hurtObj, curSkill) #吸血 CalcSuckBlood(atkObj, defObj, hurtObj, curSkill) - - TurnAttack.AddTurnObjHurtValue(atkObj, defObj, hurtValue, lostHP, curSkill) - return hurtObj + return -def CalcHurtHP(atkObj, defObj, curSkill, atkSkillValue, atkSkillPer, **atkwargs): - '''计算伤害 +def CalcHurtHP(turnFight, atkObj, defObj, curSkill, atkSkillValue, atkSkillPer, **kwargs): + '''计算伤害,默认按攻击计算 ''' pmType = GetPMType(atkObj, curSkill) ignoreDef = IsIgnoreDef(curSkill) @@ -669,7 +1000,7 @@ isTurnNormalSkill = SkillCommon.isTurnNormalSkill(curSkill) isAngerSkill = SkillCommon.isAngerSkill(curSkill) isAtkbackSkill = SkillCommon.isAtkbackSkill(curSkill) - + isDot = ("damageoftime" in kwargs) angerOverflow = 0 # 怒气溢出值 mustHit = False @@ -679,6 +1010,9 @@ angerOverflow = max(atkObj.GetXP() - IpyGameDataPY.GetFuncCfg("AngerXP", 2), 0) GameWorld.DebugLog("XP必命中! curXP=%s,angerOverflow=%s" % (curXP, angerOverflow)) + if isDot: + mustHit = True + #命中公式 攻击方类型不同,公式不同 if not mustHit: aMissRateDef = atkObj.GetBatAttrValue(ChConfig.AttrID_MissRateDef) #atkObj.GetHit() # 抗闪避率 - 命中 @@ -686,15 +1020,26 @@ missNum = defObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnMissNum) missRate = eval(IpyGameDataPY.GetFuncCompileCfg("MissCfg", 1)) if GameWorld.CanHappen(missRate): + GameWorld.DebugLog("闪避了! missRate=%s,dMissRate=%s,aMissRateDef=%s,missNum=%s" % (missRate, dMissRate, aMissRateDef, missNum)) + defObj.SetDict(ChConfig.Def_Obj_Dict_TurnMissNum, missRate + 1) return 0, pow(2, ChConfig.HurtType_Miss) hurtTypes = pow(2, ChConfig.HurtType_Normal) - isSuperHit = False # 是否暴击 + #calcType = curSkill.GetCalcType() 目前暂时按攻击算伤害,之后可以扩展其他 + + isSuperHit, isParry = False, False + aSuperDamPer, dSuperDamPerDef = 0, 0 + if not isDot: + isSuperHit = CanSuperHit(atkObj, defObj) # 是否暴击 + isParry = (isTurnNormalSkill and CanParry(atkObj, defObj)) # 是否格挡,仅针对普攻 + CanStun(turnFight, atkObj, defObj, curSkill) # 是否击晕 + if isSuperHit: hurtTypes |= pow(2, ChConfig.HurtType_SuperHit) + aSuperDamPer = atkObj.GetBatAttrValue(ChConfig.AttrID_SuperDamPer) + dSuperDamPerDef = atkObj.GetBatAttrValue(ChConfig.AttrID_SuperDamPerDef) - isParry = False # 是否格挡 if isParry: hurtTypes |= pow(2, ChConfig.HurtType_Parry) @@ -702,7 +1047,7 @@ hurtTypes |= pow(2, ChConfig.HurtType_IgnoreDef) #参与运算的数值 - rand = random.random() #种子数 0~1 + #rand = random.random() #种子数 0~1 aAtk = atkObj.GetBatAttrValue(ChConfig.AttrID_Atk) # 攻击方最大攻击 @@ -738,18 +1083,18 @@ dAngerSkillPerDef /= 10000.0 aPMDamPer /= 10000.0 dPMDamPerDef /= 10000.0 + aSuperDamPer /= 10000.0 + dSuperDamPerDef /= 10000.0 aFinalDamPer /= 10000.0 dFinalDamPerDef /= 10000.0 - GameWorld.DebugLog("伤血计算: atkID=%s,defID=%s,skillID=%s,atkSkillPer=%s,aAtk=%s,dDef=%s,dHP=%s,hurtTypes=%s" % (atkID, defID, skillID, atkSkillPer, aAtk, dDef, dHP, hurtTypes)) - if "hurtFormulaKey" in atkwargs: - aBurnValue = atkwargs.get('burnValue', 0) - aBurnPer = atkwargs.get('burnPer', 0) - hurtFormulaKey = atkwargs.get('hurtFormulaKey', None) + # 持续性伤害 + if isDot: hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("DOTFormula", 1)) + GameWorld.DebugLog(" 持续技能伤害=%s" % (hurtValue)) elif isTurnNormalSkill: hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 1)) GameWorld.DebugLog(" 普攻技能伤害=%s" % (hurtValue)) @@ -763,35 +1108,132 @@ hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 4)) GameWorld.DebugLog(" 其他伤害=%s" % (hurtValue)) + if isParry: + parryReduceRatio = IpyGameDataPY.GetFuncCfg("ParryCfg", 3) + hurtValue = hurtValue * (1 - parryReduceRatio) + GameWorld.DebugLog(" 格挡后伤害=%s,parryReduceRatio=%s" % (hurtValue, parryReduceRatio)) + hurtValue = max(1, int(hurtValue)) # 负值、保底防范 - return hurtValue, hurtTypes -def CalcBounceHP(atkObj, defObj, hurtObj, curSkill): +def CanSuperHit(atkObj, defObj): + aSuperHitRate = atkObj.GetBatAttrValue(ChConfig.AttrID_SuperHitRate) + dSuperHitRateDef = defObj.GetBatAttrValue(ChConfig.AttrID_SuperHitRateDef) + happenRate = eval(IpyGameDataPY.GetFuncCompileCfg("SuperHitCfg", 1)) + if GameWorld.CanHappen(happenRate): + GameWorld.DebugLog("暴击了: happenRate=%s,aSuperHitRate=%s,dSuperHitRateDef=%s" % (happenRate, aSuperHitRate, dSuperHitRateDef)) + return True + return False + +def CanStun(turnFight, atkObj, defObj, curSkill): + aStunRate = atkObj.GetBatAttrValue(ChConfig.AttrID_StunRate) + dStunRateDef = defObj.GetBatAttrValue(ChConfig.AttrID_StunRateDef) + happenRate = eval(IpyGameDataPY.GetFuncCompileCfg("StunCfg", 1)) + if not GameWorld.CanHappen(happenRate): + return False + GameWorld.DebugLog("击晕了: happenRate=%s,aStunRate=%s,dStunRateDef=%s" % (happenRate, aStunRate, dStunRateDef)) + stunSkillID = IpyGameDataPY.GetFuncCfg("StunCfg", 2) + TurnBuff.DoAddBuffBySkillID(turnFight, defObj, stunSkillID, atkObj, curSkill, afterLogic=True) + return True + +def CanParry(atkObj, defObj): + if defObj.IsInControlled(): + #被控制无法格挡 + return False + aParryRateDef = atkObj.GetBatAttrValue(ChConfig.AttrID_ParryRateDef) + dParryRate = defObj.GetBatAttrValue(ChConfig.AttrID_ParryRate) + parryNum = defObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnParryNum) + happenRate = eval(IpyGameDataPY.GetFuncCompileCfg("ParryCfg", 1)) + if GameWorld.CanHappen(happenRate): + GameWorld.DebugLog("格挡了: happenRate=%s,aParryRateDef=%s,dParryRate=%s,parryNum=%s" % (happenRate, aParryRateDef, dParryRate, parryNum)) + defObj.SetDict(ChConfig.Def_Obj_Dict_TurnParryNum, parryNum + 1) + return True + return False + +def CalcHurtHPWithBuff(turnFight, atkObj, defObj, curSkill, hurtValue): + ## 计算伤害后,因各种buff和状态的影响处理 + # @return: hurtValue, realHurtHP + + if hurtValue <= 0: + return 0, 0 + + # 减伤盾减伤, 会改变 hurtValue + hurtValue = max(0, hurtValue) + + # 承伤盾承伤,剩余时间短的优先承伤,承伤不影响输出,相当于额外的HP,仅用于抵扣掉血,仅 改变 realHurtHP + realHurtHP = hurtValue + shieldBuffList = [] + buffMgr = defObj.GetBuffManager() + for index in range(buffMgr.GetBuffCount()): + buff = buffMgr.GetBuffByIndex(index) + skillData = buff.GetSkillData() + # 承伤盾 + if SkillCommon.isDamageShieldSkill(skillData): + remainTime = buff.GetRemainTime() # 剩余回合 + if not skillData.GetLastTime(): + remainTime = 999 # 永久盾 + buffValue = buff.GetValue1() + buff.GetValue2() * ChConfig.Def_PerPointValue # 剩余盾值 + shieldBuffList.append([remainTime, buffValue, buff]) + + if shieldBuffList: + shieldBuffList.sort() + for _, buffValue, buff in shieldBuffList: + if realHurtHP <= 0: + break + buffID = buff.GetBuffID() + if realHurtHP < buffValue: + damageShieldValue = realHurtHP + else: + damageShieldValue = buffValue + GameWorld.DebugLog(" 承伤盾: buffID=%s,buffValue=%s,realHurtHP=%s,damageShieldValue=%s" % (buffID, buffValue, realHurtHP, damageShieldValue)) + realHurtHP -= damageShieldValue # 承伤值 + if damageShieldValue >= buffValue: + GameWorld.DebugLog(" 删除盾: buffID=%s,realHurtHP=%s" % (buffID, realHurtHP)) + TurnBuff.DoBuffDel(turnFight, defObj, buff, relatedSkill=curSkill, afterLogic=True, tagObj=atkObj) + else: + updShieldValue = buffValue - damageShieldValue + GameWorld.DebugLog(" 更新盾值: updShieldValue=%s,realHurtHP=%s" % (updShieldValue, realHurtHP)) + buff.SetValue1(updShieldValue % ChConfig.Def_PerPointValue) + buff.SetValue2(updShieldValue / ChConfig.Def_PerPointValue) + curSkill.AddAfterLogic(ChConfig.AfterLogic_SyncBuff, [defObj, buff, atkObj, "ReduceShieldValue"]) + + return hurtValue, max(0, realHurtHP) + +def CalcBounceHP(turnFight, atkObj, defObj, hurtObj, curSkill): '''计算反弹反弹伤害 ''' if not atkObj.GetCanAttack(): return bounceHP = int(hurtObj.GetHurtHP() * random.uniform(0.1, 0.2)) - if bounceHP <= 0: return - remainHP = atkObj.GetHP() - bounceHP # 反弹允许弹到负值,如果最终吸血没有吸到正值则算死亡 + GameWorld.DebugLog(" 反弹伤害=%s,%s/%s" % (bounceHP, atkObj.GetHP(), atkObj.GetMaxHP())) + bounceHP, realBounceHP = CalcHurtHPWithBuff(turnFight, defObj, atkObj, curSkill, bounceHP) + if bounceHP <= 0: + return hurtObj.SetBounceHP(bounceHP) - atkObj.SetHP(remainHP) - GameWorld.DebugLog(" 反弹伤害=%s,remainHP=%s/%s" % (bounceHP, remainHP, atkObj.GetMaxHP())) - TurnAttack.AddTurnObjHurtValue(defObj, atkObj, bounceHP, bounceHP, isBounce=True) + if realBounceHP > 0: + remainHP = atkObj.GetHP() - realBounceHP # 反弹允许弹到负值,如果最终吸血没有吸到正值则算死亡 + atkObj.SetHP(remainHP) + GameWorld.DebugLog(" bounceHP=%s,realBounceHP=%s,%s/%s" % (bounceHP, realBounceHP, atkObj.GetHP(), atkObj.GetMaxHP())) + + TurnAttack.AddTurnObjHurtValue(defObj, atkObj, bounceHP, realBounceHP, isBounce=True) return def CalcSuckBlood(atkObj, defObj, hurtObj, curSkill): '''计算吸血 ''' - suckHP = int(hurtObj.GetHurtHP() * random.uniform(0.1, 0.2)) + hurtHP = hurtObj.GetHurtHP() + if hurtHP <= 1: + return + aSuckHPPer = atkObj.GetBatAttrValue(ChConfig.AttrID_SuckHPPer) + dSuckHPPerDef = defObj.GetBatAttrValue(ChConfig.AttrID_SuckHPPerDef) + suckHP = int(eval(IpyGameDataPY.GetFuncCompileCfg("SuckHPCfg", 1))) if suckHP <= 0: return @@ -802,7 +1244,7 @@ hurtObj.SetSuckHP(suckHP) atkObj.SetHP(remainHP) - GameWorld.DebugLog(" 吸血=%s,remainHP=%s/%s" % (suckHP, remainHP, maxHP)) + GameWorld.DebugLog(" 吸血=%s,remainHP=%s/%s,aSuckHPPer=%s,dSuckHPPerDef=%s" % (suckHP, remainHP, maxHP, aSuckHPPer, dSuckHPPerDef)) # 吸血暂定算治疗 TurnAttack.AddTurnObjCureHP(atkObj, atkObj, suckHP, cureHP) @@ -811,21 +1253,12 @@ def CalcCureHP(userObj, tagObj, curSkill, largeNum=False): ''' 计算治疗值 ''' - cureBaseValue = 0 #治疗基础值 - effect = SkillCommon.GetSkillEffectByEffectID(curSkill, ChConfig.Def_Skill_Effect_Cure) - skillPer = effect.GetEffectValue(0) if effect else 0 - cureType = effect.GetEffectValue(1) if effect else 0 + cureType = curSkill.GetCalcType() + skillPer = curSkill.GetSkillPer() + #skillValue = curSkill.GetSkillValue() - #获得基础治疗值 - if cureType == ChConfig.Def_Cure_Attack: - cureBaseValue = userObj.GetAtk() - elif cureType == ChConfig.Def_Cure_MaxHP: - cureBaseValue = userObj.GetMaxHP() - #elif cureType == ChConfig.Def_Cure_HurtValue: - # cureBaseValue = GameObj.GetLastHurtValue(userObj) - elif cureType == ChConfig.Def_Cure_TagMaxHP: - cureBaseValue = 0 if not tagObj else tagObj.GetMaxHP() - + cureBaseValue = GetCalcBaseValue(cureType, userObj, tagObj) + #skillPer += PassiveBuffEffMng.GetPassiveSkillValueByTriggerType(userObj, None, curSkill, ChConfig.TriggerType_AddHP) # 回合制 @@ -838,7 +1271,7 @@ #curePer += GameObj.GetCurePer(userObj) #if enemyObj: # cureDefPer += GameObj.GetCureDefPer(enemyObj) - + skillPer /= float(ChConfig.Def_MaxRateValue) curePer /= float(ChConfig.Def_MaxRateValue) cureDefPer /= float(ChConfig.Def_MaxRateValue) @@ -854,6 +1287,69 @@ GameWorld.DebugLog("计算治疗值(%s):skillID=%s,cureType=%s,baseValue=%s,skillPer=%s,curePer=%s,cureDefPer=%s,angerOverflow=%s" % (cureHP, curSkill.GetSkillID(), cureType, baseValue, skillPer, curePer, cureDefPer, angerOverflow)) return cureHP + +def GetCalcBaseValue(calcType, curObj, tagObj): + ##获得基础计算值 + if calcType == ChConfig.Def_Calc_Attack: + baseValue = curObj.GetAtk() + elif calcType == ChConfig.Def_Calc_MaxHP: + baseValue = curObj.GetMaxHP() + #elif cureType == ChConfig.Def_Calc_HurtValue: + # baseValue = GameObj.GetLastHurtValue(userObj) + elif calcType == ChConfig.Def_Calc_TagMaxHP: + baseValue = 0 if not tagObj else tagObj.GetMaxHP() + return baseValue + +def DoDOTAttack(turnFight, batObj, curBuff, hurtValue, hurtTypes): + ## 执行单次dot逻辑 + skillID = curBuff.GetSkillID() + skillIpyData = IpyGameDataPY.GetIpyGameData("Skill", skillID) + if not skillIpyData: + return + buffID = curBuff.GetBuffID() + ownerID = curBuff.GetOwnerID() + buffOwner = BattleObj.GetBatObjMgr().getBatObj(ownerID) # 攻击方 + + atkObj = buffOwner + defObj = batObj + + defID = defObj.GetID() + tagObjList = [defObj] + + poolMgr = ObjPool.GetPoolMgr() + useSkill = poolMgr.acquire(BattleObj.PySkill, skillIpyData) + useSkill.SetTagObjList(tagObjList) + useSkill.ClearHurtObj() + hurtObj = useSkill.AddHurtObj(defID) + + dHP = defObj.GetHP() + GameWorld.DebugLog("结算dot: defID=%s,buffID=%s,skillID=%s,ownerID=%s,hurtValue=%s,hurtTypes=%s,dHP=%s" + % (defID, buffID, skillID, ownerID, hurtValue, hurtTypes, dHP)) + hurtValue, realHurtHP = CalcHurtHPWithBuff(turnFight, atkObj, defObj, useSkill, hurtValue) + + # dot的反弹、吸血待定 + + remainHP = max(0, dHP - realHurtHP) # 剩余血量 + lostHP = dHP - remainHP # 实际掉血量 + defObj.SetHP(remainHP) + + GameWorld.DebugLog(" hurtValue=%s,realHurtHP=%s,lostHP=%s,%s/%s" % (hurtValue, realHurtHP, lostHP, defObj.GetHP(), defObj.GetMaxHP())) + + hurtObj.SetHurtTypes(hurtTypes) + hurtObj.SetHurtHP(hurtValue) + hurtObj.SetRealHurtHP(realHurtHP) + hurtObj.SetLostHP(lostHP) + hurtObj.SetCurHP(remainHP) + + TurnAttack.AddTurnObjHurtValue(atkObj, batObj, hurtValue, lostHP, skillID) + + Sync_PropertyRefreshView(turnFight, defObj, ChConfig.AttrID_HP, remainHP, hurtValue, diffType=0, skillID=skillID, hurtTypes=hurtTypes) + + DoBeAttackResult(turnFight, atkObj, useSkill) + + useSkill.ResetUseRec() + poolMgr.release(useSkill) + return def Sync_UseSkill(turnFight, curBatObj, useSkill): ## 通知释放技能 @@ -881,13 +1377,14 @@ turnFight.addBatPack(clientPack) return -def Sync_PropertyRefreshView(turnFight, curBatObj, attrID, value, diffValue, diffType=0, skillID=0, relatedSkillID=0): +def Sync_PropertyRefreshView(turnFight, curBatObj, attrID, value, diffValue, diffType=0, skillID=0, relatedSkillID=0, hurtTypes=0): '''通知对象属性刷新展示B418 @param attrID: 通知变化的属性ID @param diffValue: 变化值 @param diffType: 变化类型,0-减少;1-增加 @param skillID: 使用的技能表ID,即哪个技能的效果 @param relatedSkillID: 关联的技能ID,一般是主技能ID,非主技能额外触发的为0 + @param hurtTypes: 飘字类型汇总,支持多种类型并存,如无视防御且暴击同时被格挡,二进制或运算最终值;0-失败;1-普通;2-回血;5-格挡;6-无视防御;7-暴击;9-闪避 ''' if attrID not in ChConfig.CDBRefresh_AttrIDDict: return @@ -896,6 +1393,7 @@ clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCObjPropertyRefreshView) clientPack.ObjID = curBatObj.GetID() clientPack.RefreshType = refreshType + clientPack.AttackTypes = hurtTypes if isBig: clientPack.Value = value % ShareDefine.Def_PerPointValue clientPack.ValueEx = value / ShareDefine.Def_PerPointValue -- Gitblit v1.8.0