From 0c96af08f55d05ab40eae9f940467dd8eafae44c Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期二, 16 九月 2025 14:07:53 +0800
Subject: [PATCH] 129 【战斗】战斗系统-服务端(增加属性ID技能增伤65、技能减伤66;曹轶技能;被动触发增加属性支持;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerOnline.py |  172 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 135 insertions(+), 37 deletions(-)

diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerOnline.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerOnline.py
index 0c96bc7..2f18a62 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerOnline.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerOnline.py
@@ -16,6 +16,7 @@
 #"""Version = 2025-07-02 17:30"""
 #-------------------------------------------------------------------------------
 
+import BattleObj
 import TurnAttack
 import PyGameData
 import ShareDefine
@@ -30,7 +31,7 @@
 import time
 
 class LineupHero():
-    ## 阵容战斗武将,注意:同一个武将在不同阵容中可能属性不一样
+    ## 阵容武将,注意:同一个武将在不同阵容中可能属性不一样
     
     def __init__(self):
         self.Clear()
@@ -39,10 +40,12 @@
     def Clear(self):
         self.itemIndex = 0
         self.heroID = 0
+        self.skinID = 0
         self.posNum = 0
         self.heroBatAttrDict = {} # 武将的最终战斗属性字典, {attrID:value, ...}
         self.heroSkillIDList = [] # 武将拥有的技能ID列表 [skillID, ...]
         self.fightPower = 0 # 武将最终战力
+        self.skillFightPower = 0 # 技能战力
         return
     
 class Lineup():
@@ -54,6 +57,7 @@
         self.olPlayer = None
         self.shapeType = 0
         self.heroItemDict = {} # 阵容武将背包索引信息  {itemIndex:posNum, ...}
+        self.lineupChange = False # 是否已变更阵容标记,在刷新属性后重置标记
         self.__refreshState = 0 # 刷属性标记, 0-不需要刷新了,1-需要刷新
         
         self.__freeLineupHeroObjs = [] # 释放的空闲对象[LineupHero, ...]
@@ -61,16 +65,20 @@
         self.fightPower = 0 # 阵容总战力
         return
     
-    def UpdLineup(self, heroItemDict, shapeType=0, refreshForce=False):
+    def UpdLineup(self, heroItemDict, shapeType=0, refreshForce=False, isReload=False):
         '''变更阵容时更新
         @param heroItemDict: 武将背包索引信息  {itemIndex:posNum, ...}
         @param shapeType: 阵型
         @param refreshForce: 是否强制刷属性
         '''
+        if not isReload: # 非重读阵容的视为变更
+            self.lineupChange = True
         self.shapeType = shapeType
         self.heroItemDict = heroItemDict
         GameWorld.DebugLog("更新阵容: lineupID=%s,%s" % (self.lineupID, heroItemDict), self.playerID)
         self.RefreshLineupAttr(refreshForce)
+        if not isReload and self.olPlayer.curPlayer:
+            PlayerHero.Sync_Lineup(self.olPlayer.curPlayer, self.lineupID)
         return
     
     def FreeLineupHero(self):
@@ -96,11 +104,14 @@
         return lineupHero
     
     def GetLineupHeroByID(self, heroID):
+        lineupHero = None
         for posNum in self.lineupHeroDict.keys():
-            lineup = self.GetLineupHero(posNum)
-            if lineup.heroID == heroID:
-                return lineup
-        return
+            lineupHero = self.GetLineupHero(posNum)
+            if lineupHero.heroID == heroID:
+                return lineupHero
+        if False:
+            lineupHero = LineupHero()
+        return lineupHero
     
     def GetLineupInfo(self):
         ## 获取阵容信息,即要用到该阵容了,如战斗或者保存缓存信息等
@@ -122,6 +133,7 @@
         if not self.__refreshState:
             return False
         doRefreshLineupAttr(self.olPlayer.curPlayer, self.olPlayer, self)
+        self.lineupChange = False
         self.__refreshState = 0
         return True
     
@@ -144,10 +156,12 @@
         
         # 主线战斗
         self.mainFight = TurnAttack.MainFight(playerID)
+        
+        self._lastBatBufferInfo = [] # 最后一场战斗临时回放 ["guid", "buffer"]
         return
     
     def OnClear(self):
-        self.mainFight.clear()
+        self.mainFight.turnFight.exitFight()
         return
     
     def SetPlayer(self, curPlayer):
@@ -234,6 +248,11 @@
                         
         GameWorld.DebugLog("武将物品养成更新索引: %s, 影响阵容:%s" % (itemIndexList, effLineupIDList), self.playerID)
         return effLineupIDList
+    
+    def GetLastBatBuffer(self): return self._lastBatBufferInfo
+    def SetLastBatBuffer(self, guid, batBuffer):
+        self._lastBatBufferInfo = [guid, batBuffer]
+        return
     
 class OnlineMgr():
     ## 准在线玩家管理
@@ -380,8 +399,9 @@
         # 获取其他绑定该阵容的功能,如红颜、灵兽等
         
         shapeType = lineShapeTypeDict.get(lineupID, 0)
-        lineup.UpdLineup(heroItemDict, shapeType)
+        lineup.UpdLineup(heroItemDict, shapeType, isReload=True)
         
+    PlayerHero.Sync_Lineup(curPlayer)
     return
 
 def doCalcAllAttr(curPlayer):
@@ -446,11 +466,20 @@
         star = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroStar)
         breakLV = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroBreakLV)
         awakeLV = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroAwakeLV)
+        skinIndex = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroSkin)
         
+        skinID = 0
+        skinIDList = heroIpyData.GetSkinIDList()
+        if skinIndex < 0 or skinIndex >= len(skinIDList):
+            skinID = skinIDList[skinIndex]
+        elif skinIDList:
+            skinID = skinIDList[0]
+            
+        starMax = PlayerHero.GetHeroStarMax(heroItem)
         InitAddPer += qualityIpyData.GetInitAddPer()
-        LVAddPer += qualityIpyData.GetLVAddPer() * heroLV
+        LVAddPer += qualityIpyData.GetLVAddPer() * max(0, heroLV - 1)
         BreakLVAddPer += qualityIpyData.GetBreakLVAddPer() * breakLV
-        StarAddPer += qualityIpyData.GetStarAddPer() * star
+        StarAddPer += qualityIpyData.GetStarAddPer() * min(star, starMax)
         
         lineupHero = lineup.GetLineupHero(posNum)
         #if False:
@@ -458,6 +487,7 @@
         lineupHero.itemIndex = itemIndex
         lineupHero.posNum = posNum
         lineupHero.heroID = heroID
+        lineupHero.skinID = skinID
         lineupHero.heroBatAttrDict = {}
         lineupHero.heroSkillIDList = []
         lineupHero.fightPower = 0
@@ -476,26 +506,11 @@
             selfAttrDict[int(k)] = v
         heroSelfAttrInfo[heroID] = selfAttrDict
         
-        # 星级天赋
-        starTalentAttrDict = {}
-        idCount = heroItem.GetUserAttrCount(ShareDefine.Def_IudetHeroTalentID)
-        lvCount = heroItem.GetUserAttrCount(ShareDefine.Def_IudetHeroTalentIDLV)
-        for aIndex in range(min(idCount, lvCount)):
-            talentID = heroItem.GetUserAttrByIndex(ShareDefine.Def_IudetHeroTalentID, aIndex)
-            talentLV = heroItem.GetUserAttrByIndex(ShareDefine.Def_IudetHeroTalentIDLV, aIndex)
-            stIpyData = IpyGameDataPY.GetIpyGameData("HeroTalent", talentID)
-            if not stIpyData:
-                continue
-            attrID = stIpyData.GetAttrID()
-            attrValue = stIpyData.GetAttrValue() * talentLV
-            starTalentAttrDict[attrID] = starTalentAttrDict.get(attrID, 0) + attrValue
-        heroStarTalentInfo[heroID] = starTalentAttrDict
-        
         # 突破潜能
         breakAttrDict = {}
-        awakeIpyDataList = IpyGameDataPY.GetIpyGameDataList("HeroBreak", heroID)
-        if awakeIpyDataList:
-            for breakIpyData in awakeIpyDataList:
+        breakIpyDataList = IpyGameDataPY.GetIpyGameDataList("HeroBreak", heroID)
+        if breakIpyDataList:
+            for breakIpyData in breakIpyDataList:
                 if breakIpyData.GetBreakLV() > breakLV:
                     break
                 attrIDList = breakIpyData.GetAttrIDList()
@@ -510,12 +525,15 @@
         heroBreakAttrInfo[heroID] = breakAttrDict
         
         # 觉醒天赋
+        maxUnlockSlot = IpyGameDataPY.GetFuncCfg("HeroStarTalent", 1) # 常规天赋槽个数
         awakeTalentAttrDict = {}
-        awakeIpyDataList = IpyGameDataPY.GetIpyGameDataList("HeroAwake", heroID)
+        awakeIpyDataList = IpyGameDataPY.GetIpyGameDataListNotLog("HeroAwake", heroID)
         if awakeIpyDataList:
             for awakeIpyData in awakeIpyDataList:
                 if awakeIpyData.GetAwakeLV() > awakeLV:
                     break
+                unlockTalentSlot = awakeIpyData.GetUnlockTalentSlot()
+                maxUnlockSlot = max(maxUnlockSlot, unlockTalentSlot)
                 attrIDList = awakeIpyData.GetAttrIDList()
                 attrValueList = awakeIpyData.GetAttrValueList()
                 for aIndex in range(min(len(attrIDList), len(attrValueList))):
@@ -526,6 +544,21 @@
                 if skillID:
                     lineupHero.heroSkillIDList.append(skillID)
         heroAwakeTalentInfo[heroID] = awakeTalentAttrDict
+        
+        # 星级天赋
+        starTalentAttrDict = {}
+        idCount = heroItem.GetUserAttrCount(ShareDefine.Def_IudetHeroTalentID)
+        lvCount = heroItem.GetUserAttrCount(ShareDefine.Def_IudetHeroTalentIDLV)
+        for aIndex in range(min(idCount, lvCount, maxUnlockSlot)): # 重生导致已觉醒槽位失效时属性也无效
+            talentID = heroItem.GetUserAttrByIndex(ShareDefine.Def_IudetHeroTalentID, aIndex)
+            talentLV = heroItem.GetUserAttrByIndex(ShareDefine.Def_IudetHeroTalentIDLV, aIndex)
+            stIpyData = IpyGameDataPY.GetIpyGameData("HeroTalent", talentID)
+            if not stIpyData:
+                continue
+            attrID = stIpyData.GetAttrID()
+            attrValue = stIpyData.GetAttrValue() * talentLV
+            starTalentAttrDict[attrID] = starTalentAttrDict.get(attrID, 0) + attrValue
+        heroStarTalentInfo[heroID] = starTalentAttrDict
         
         # 羁绊统计
         for fetterID in heroIpyData.GetFetterIDList():
@@ -593,6 +626,7 @@
     baseAttrFormula = IpyGameDataPY.GetFuncCfg("HeroAttrFormula", 1)
     otherAttrFormula = IpyGameDataPY.GetFuncCfg("HeroAttrFormula", 2)
     fightPowerFormula = IpyGameDataPY.GetFuncCfg("HeroAttrFormula", 3)
+    skillFPFormula = IpyGameDataPY.GetFuncCfg("HeroAttrFormula", 4)
     
     lvAttrDict = olPlayer.GetCalcAttr(ChConfig.Def_CalcAttr_LV)
     equipAttrDict = olPlayer.GetCalcAttr(ChConfig.Def_CalcAttr_MainEquip)
@@ -611,6 +645,12 @@
     GameWorld.DebugLog("    主公等级属性=%s" % lvAttrDict, playerID)
     GameWorld.DebugLog("    主公装备属性=%s" % equipAttrDict, playerID)
     GameWorld.DebugLog("    主公图鉴属性=%s" % bookAttrDict, playerID)
+    
+    PlayerLV = curPlayer.GetLV()
+    OfficialLV = curPlayer.GetOfficialRank()
+    GameWorld.DebugLog("    PlayerLV=%s,OfficialLV=%s" % (PlayerLV, OfficialLV), playerID)
+    
+    fpRatioIpyData = IpyGameDataPY.GetIpyGameData("FightPowerRatio", OfficialLV)
     
     lineupFightPower = 0 # 阵容总战力
     InitAddPer, LVAddPer, BreakLVAddPer, StarAddPer = InitAddPer / 10000.0, LVAddPer / 10000.0, BreakLVAddPer / 10000.0, StarAddPer / 10000.0
@@ -644,8 +684,8 @@
             inheritPer = 1 # 继承比例,默认100%
             if attrID in ChConfig.AttrInheritPerDict:
                 attrInheritPerID = ChConfig.AttrInheritPerDict[attrID] # 继承ID
-                inheritPer = selfAttrDict.get(attrInheritPerID, 100) # 继承比例从武将自身属性中取
-                inheritPer /= 100.0
+                inheritPer = selfAttrDict.get(attrInheritPerID, 10000) # 继承比例从武将自身属性中取
+                inheritPer /= 10000.0
                 
             lineupHaloValue, lineupHaloPer = lineupHaloAttrInfo.get(attrID, 0), 0
             fetterValue, fetterPer = fetterAttrDict.get(attrID, 0), 0
@@ -674,23 +714,51 @@
             else:
                 attrValue = FormulaControl.Eval("otherAttrFormula", otherAttrFormula, attrParamDict)
             #GameWorld.DebugLog("    attrID=%s,attrValue=%s,attrParamDict=%s" % (attrID, attrValue, attrParamDict))
-            lineupHero.heroBatAttrDict[attrID] = attrValue
             
             attrIpyData = IpyGameDataPY.GetIpyGameData("PlayerAttr", attrID)
             attrName = attrIpyData.GetParameter() if attrIpyData else "%s" % attrID
+            attrRatioName = "%sRatio" % attrName
+            ratioValue = 0
+            if attrValue and hasattr(fpRatioIpyData, "Get%s" % attrRatioName):
+                ratioValue = getattr(fpRatioIpyData, "Get%s" % attrRatioName)()
             fightPowerParamDict[attrName] = attrValue
+            fightPowerParamDict[attrRatioName] = ratioValue
             if attrValue:
+                lineupHero.heroBatAttrDict[attrID] = attrValue
                 logAttrDict["%s-%s" % (attrID, attrName)] = attrValue
-                
+            
         # 计算战力
         fightPower = FormulaControl.Eval("fightPowerFormula", fightPowerFormula, fightPowerParamDict)
-        skillFightPower = 0
+        
+        GameWorld.DebugLog("    heroID=%s,fightPower=%s,heroSkillIDList=%s" % (heroID, fightPower, lineupHero.heroSkillIDList), playerID)
+        skillTypeIDDict = {}
         for skillID in lineupHero.heroSkillIDList:
-            skillData = GameWorld.GetGameData().GetSkillBySkillID(skillID)
+            skillData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
             if not skillData:
                 continue
-            skillFightPower += skillData.GetFightPower()
+            skillTypeID = skillData.GetSkillTypeID()
+            if skillTypeID not in skillTypeIDDict:
+                skillTypeIDDict[skillTypeID] = skillData
+            else:
+                befSkillData = skillTypeIDDict[skillTypeID]
+                befSkillID = befSkillData.GetSkillID()
+                if befSkillID >= skillID:
+                    continue
+                skillTypeIDDict[skillTypeID] = skillData
+                
+        skillFightPower = 0
+        lineupHero.heroSkillIDList = []
+        for skillData in skillTypeIDDict.values():
+            skillID = skillData.GetSkillID()
+            lineupHero.heroSkillIDList.append(skillID)
+            paramDict = {"SkillPower":skillData.GetFightPower(), "PlayerLV":PlayerLV, "OfficialLV":OfficialLV}
+            sFightPower = FormulaControl.Eval("skillFPFormula", skillFPFormula, paramDict)
+            skillFightPower += sFightPower
+        GameWorld.DebugLog("    skillFightPower=%s,heroSkillIDList=%s" % (skillFightPower, lineupHero.heroSkillIDList), playerID)
+        
+        # 最终战力
         fightPowerTotal = fightPower + skillFightPower
+        lineupHero.skillFightPower = skillFightPower
         lineupHero.fightPower = fightPowerTotal
         lineupFightPower += fightPowerTotal
         
@@ -700,10 +768,40 @@
     lineup.fightPower = lineupFightPower
     GameWorld.DebugLog("    阵容最终战力: lineupID=%s,lineupFightPower=%s" % (lineupID, lineupFightPower), playerID)
     
-    # 更新排行榜
+    # 非主线阵容不处理以下内容
     if lineupID != ShareDefine.Lineup_Main:
         return
     
     PlayerControl.SetFightPower(curPlayer, lineupFightPower)
     
+    mainFightMgr = TurnAttack.GetMainFightMgr(curPlayer)
+    mainTurnFight = mainFightMgr.turnFight
+    # 主线战斗如果有在战斗中,实时更新
+    if mainTurnFight and mainTurnFight.isInFight():
+        # 如果是阵容变化的,重新开始战斗
+        if lineup.lineupChange:
+            GameWorld.DebugLog("主阵容变化,重新开始战斗", playerID)
+            if mainTurnFight.mapID == ChConfig.Def_FBMapID_Main:
+                TurnAttack.__doMainLevelWave(curPlayer, True)
+                
+        # 否则只重新设置战斗属性
+        else:
+            GameWorld.DebugLog("主阵容卡牌属性变更,更新战斗武将属性", playerID)
+            # lineup        为卡牌的阵容,仅有阵容属性相关,没有战斗对象
+            # batLineup    为卡牌阵容体现到具体战斗的战斗阵容,有具体的战斗对象
+            faction, num = ChConfig.Def_FactionA, 1 # 主线战斗玩家自己默认阵营A的第1个战斗阵容
+            batLineup = mainTurnFight.getBatFaction(faction).getBatlineup(num)
+            batObjMgr = BattleObj.GetBatObjMgr()
+            for posNum, objID in batLineup.posObjIDDict.items():
+                batObj = batObjMgr.getBatObj(objID)
+                if not batObj:
+                    continue
+                lineupHero = lineup.GetLineupHero(posNum)
+                if lineupHero.heroBatAttrDict:
+                    batObj.UpdInitBatAttr(lineupHero.heroBatAttrDict, lineupHero.heroSkillIDList)
+    else:
+        GameWorld.DebugLog("主阵容没有在战斗中,不需要处理", playerID)
+        
+    # 更新排行榜
+    
     return

--
Gitblit v1.8.0