hxp
2026-01-06 34520d2b2a4ac78f832169b7ea120651b7f43c26
412 【挑战】定军阁-服务端(效果属性暂时无效;)
2个文件已添加
10个文件已修改
1155 ■■■■■ 已修改文件
PySysDB/PySysDBPY.h 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Dingjunge.py 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_Dingjunge.py 582 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFB.py 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h
@@ -1171,6 +1171,35 @@
    list        RandWeightItemList;    //宝箱随机物品权重列表,[[权重,物品ID,数量], ...]
};
//定军阁关卡表
struct    FBDJGLevel
{
    WORD        _LayerNum;    //层数
    BYTE        _LevelNum;    //关卡编号
    list        PassAwardList;    // 过关奖励列表,[[物品ID,个数], ...]
    list        AwardList;    // 挑战奖励,[[物品ID,个数], ...]
    list        LineupIDList;    // 阵容ID列表,小队1阵容ID|小队2阵容ID|...
    WORD        NPCLV;    //NPC等级
    float        Difficulty;    //难度系数
};
//定军阁速战奖励表
struct    FBDJGQuick
{
    WORD        _NeedLayer;    //所需层数
    list        QuickAwardList;    // 速战奖励列表,[[物品ID,个数], ...]
};
//定军阁效果表
struct    FBDJGEffect
{
    DWORD        _EffID;    //效果ID
    BYTE        EffQuality;    // 效果品质
    BYTE        AttrID;    // 属性ID
    DWORD        AttrValue;    // 属性值
    DWORD        RandWeight;    // 随机权重
};
//广告奖励表
struct ADAward
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1183,6 +1183,22 @@
PacketSubCMD_1=0x15
PacketCallFunc_1=OnMainDropItemOP
;定军阁
[GameLogic_Dingjunge]
ScriptName = GameWorldLogic\FBProcess\GameLogic_Dingjunge.py
Writer = hxp
Releaser = hxp
RegType = 0
RegisterPackCount = 2
PacketCMD_1=0xB1
PacketSubCMD_1=0x01
PacketCallFunc_1=OnDingjungeEffSet
PacketCMD_2=0xB1
PacketSubCMD_2=0x02
PacketCallFunc_2=OnDingjungeEffSelect
;回合攻击
[TurnAttack]
ScriptName = Attack\TurnAttack.py
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -1087,13 +1087,14 @@
    if not reqRet:
        return
    funcLineID = reqRet[1] if len(reqRet) > 1 else funcLineID
    GameWorld.DebugLogEx("    funcLineID=%s", funcLineID, playerID)
    
    fbIpyData = FBCommon.GetFBIpyData(mapID)
    fbLineIpyData = FBCommon.GetFBLineIpyData(mapID, funcLineID, False)
    if fbIpyData:
        if not fbLineIpyData:
            GameWorld.DebugLogEx("不存在该副本功能线路! mapID=%s,funcLineID=%s", mapID, funcLineID)
            return
        #if not fbLineIpyData:
        #    GameWorld.DebugLogEx("不存在该副本功能线路! mapID=%s,funcLineID=%s", mapID, funcLineID)
        #    return
        if FBCommon.CheckCanEnterFBComm(curPlayer, mapID, funcLineID, fbIpyData, fbLineIpyData) != ShareDefine.EntFBAskRet_OK:
            return
        
@@ -1277,7 +1278,7 @@
    
    for index, lineupID in enumerate(npcLineupIDList):
        turnFight.lineupIndex = index
        GameWorld.DebugLogEx("对战NPC阵容: index=%s, lineupID=%s", index, lineupID)
        GameWorld.DebugLogEx("对战NPC阵容: mapID=%s,funcLineID=%s,index=%s,lineupID=%s", mapID, funcLineID, index, lineupID)
        if index > 0:
            turnFight.nextTurnFight()
        turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:GetNPCLineupInfo(lineupID, strongerLV, difficulty)})
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -1897,9 +1897,10 @@
Def_FBMapID_Zhanchui = 30010 # 白骨盈野/战锤秘境
Def_FBMapID_Tianzi = 30020 # 天子考验
Def_FBMapID_Dingjunge = 30030 # 定军阁
#线路未过关时免费的地图
UnPassFreeMapIDList = [Def_FBMapID_Zhanchui]
UnPassFreeMapIDList = [Def_FBMapID_Zhanchui, Def_FBMapID_Dingjunge]
#按星级记录过关的地图
PassByStarMapIDList = []
#扫荡不需要检查是否已过关的地图
@@ -1907,7 +1908,7 @@
#固定玩家获胜的地图
PlayerWinMapIDList = [Def_FBMapID_Tianzi]
#需要汇报中心副本过关进度的地图
ReportCenterMapIDList = [Def_FBMapID_Zhanchui]
ReportCenterMapIDList = [Def_FBMapID_Zhanchui, Def_FBMapID_Dingjunge]
#注册上传跨服服务器数据后直接进入跨服服务器的地图
RegisterEnter_CrossServerMapIDList = []
@@ -1981,6 +1982,7 @@
                'Arena':[Def_FBMapID_ArenaBattle],
                'Zhanchui':[Def_FBMapID_Zhanchui],
                'Tianzi':[Def_FBMapID_Tianzi],
                'Dingjunge':[Def_FBMapID_Dingjunge],
                }
#特殊副本ID, 由系统分配, 进入时候不验证IsMapCopyFull
@@ -3885,6 +3887,15 @@
Def_PDict_TianziHisHurtEx = "TianziHisHurtEx_%s" # 历史最高伤害,整除亿部分,参数(bossID)
Def_PDict_TianziTodayHurt = "TianziTodayHurt" # 今日最高伤害,求余亿部分
Def_PDict_TianziTodayHurtEx = "TianziTodayHurtEx" # 今日最高伤害,整除亿部分
#定军阁
Def_PDict_DJGLineID = "DJGLineID"  # 今日已过关的线路ID 层 * 100 + 关卡编号
Def_PDict_DJGEffect = "DJGEff_%s"  # 已生效的加成效果,参数(index)  effID * 100 + 效果等级
Def_PDict_DJGSelectEffect = "DJGSelectEff_%s"  # 当前待选择的加成效果,参数(index) effID
Def_PDict_DJGUnSelectCnt = "DJGUnSelectCnt"  # 还有几个未选择的效果
Def_PDict_DJGEffAuto = "DJGEffAuto"  # 是否自动选择效果
Def_PDict_DJGEffSet = "DJGEffSet_%s"  # 预设优先选择属性ID,参数(优先index)
#-------------------------------------------------------------------------------
#物品效果(ID或指定类型)对应的属性计算信息 {效果(ID/指定类型):[[属性索引, ...], 是否基础属性,(非)线性]}
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -10984,6 +10984,140 @@
#------------------------------------------------------
# B1 02 定军阁效果选择 #tagCSDingjungeEffSelect
class  tagCSDingjungeEffSelect(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("SelectType", c_ubyte),    #0-手动选择,1-放弃本次选择,2-一键选择(仅开启了自动选择时有效)
                  ("SelectIndex", c_ubyte),    #手动选择索引 0~n
                  ("ReplaceHole", c_ubyte),    #手动选择替换槽位 1~n,槽位=槽索引+1,升级时可直接发0
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB1
        self.SubCmd = 0x02
        return
    def ReadData(self, stringData, _pos=0, _len=0):
        self.Clear()
        memmove(addressof(self), stringData[_pos:], self.GetLength())
        return _pos + self.GetLength()
    def Clear(self):
        self.Cmd = 0xB1
        self.SubCmd = 0x02
        self.SelectType = 0
        self.SelectIndex = 0
        self.ReplaceHole = 0
        return
    def GetLength(self):
        return sizeof(tagCSDingjungeEffSelect)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B1 02 定军阁效果选择 //tagCSDingjungeEffSelect:
                                Cmd:%s,
                                SubCmd:%s,
                                SelectType:%d,
                                SelectIndex:%d,
                                ReplaceHole:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.SelectType,
                                self.SelectIndex,
                                self.ReplaceHole
                                )
        return DumpString
m_NAtagCSDingjungeEffSelect=tagCSDingjungeEffSelect()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCSDingjungeEffSelect.Cmd,m_NAtagCSDingjungeEffSelect.SubCmd))] = m_NAtagCSDingjungeEffSelect
#------------------------------------------------------
# B1 01 定军阁效果预设 #tagCSDingjungeEffSet
class  tagCSDingjungeEffSet(Structure):
    Head = tagHead()
    SelectAuto = 0    #(BYTE SelectAuto)//是否启用自动选择
    SelectSetCnt = 0    #(BYTE SelectSetCnt)
    SelectSetAttrIDList = list()    #(vector<WORD> SelectSetAttrIDList)//预设优先选择属性ID列表 [优先级1属性ID, ...]
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xB1
        self.Head.SubCmd = 0x01
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.SelectAuto,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.SelectSetCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.SelectSetCnt):
            value,_pos=CommFunc.ReadWORD(_lpData,_pos)
            self.SelectSetAttrIDList.append(value)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xB1
        self.Head.SubCmd = 0x01
        self.SelectAuto = 0
        self.SelectSetCnt = 0
        self.SelectSetAttrIDList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += 1
        length += 2 * self.SelectSetCnt
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.SelectAuto)
        data = CommFunc.WriteBYTE(data, self.SelectSetCnt)
        for i in range(self.SelectSetCnt):
            data = CommFunc.WriteWORD(data, self.SelectSetAttrIDList[i])
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                SelectAuto:%d,
                                SelectSetCnt:%d,
                                SelectSetAttrIDList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.SelectAuto,
                                self.SelectSetCnt,
                                "..."
                                )
        return DumpString
m_NAtagCSDingjungeEffSet=tagCSDingjungeEffSet()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCSDingjungeEffSet.Head.Cmd,m_NAtagCSDingjungeEffSet.Head.SubCmd))] = m_NAtagCSDingjungeEffSet
#------------------------------------------------------
# B1 08 快速一键过关副本 #tagCMFBQuickPass
class  tagCMFBQuickPass(Structure):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -33232,6 +33232,173 @@
#------------------------------------------------------
# B2 02 定军阁信息 #tagSCDingjungeInfo
class  tagSCDingjungeEff(Structure):
    _pack_ = 1
    _fields_ = [
                  ("EffIndex", c_ubyte),    #槽索引,0~n
                  ("EffID", c_ushort),
                  ("EffLV", c_ubyte),
                  ]
    def __init__(self):
        self.Clear()
        return
    def ReadData(self, stringData, _pos=0, _len=0):
        self.Clear()
        memmove(addressof(self), stringData[_pos:], self.GetLength())
        return _pos + self.GetLength()
    def Clear(self):
        self.EffIndex = 0
        self.EffID = 0
        self.EffLV = 0
        return
    def GetLength(self):
        return sizeof(tagSCDingjungeEff)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B2 02 定军阁信息 //tagSCDingjungeInfo:
                                EffIndex:%d,
                                EffID:%d,
                                EffLV:%d
                                '''\
                                %(
                                self.EffIndex,
                                self.EffID,
                                self.EffLV
                                )
        return DumpString
class  tagSCDingjungeInfo(Structure):
    Head = tagHead()
    TodayPass = 0    #(DWORD TodayPass)//今日过关进度 层*100+关卡编号,历史最高过关记录取A320中的PassLineID
    EffCnt = 0    #(BYTE EffCnt)
    EffList = list()    #(vector<tagSCDingjungeEff> EffList)//已生效的效果列表
    SelectEffCnt = 0    #(BYTE SelectEffCnt)
    SelectEffList = list()    #(vector<DWORD> SelectEffList)//待手动选择的效果ID列表
    UnSelectCnt = 0    #(WORD UnSelectCnt)//还有几个未选择的效果
    SelectAuto = 0    #(BYTE SelectAuto)//是否启用自动选择
    SelectSetCnt = 0    #(BYTE SelectSetCnt)
    SelectSetAttrIDList = list()    #(vector<WORD> SelectSetAttrIDList)//预设优先选择属性ID列表 [优先级1属性ID, ...]
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xB2
        self.Head.SubCmd = 0x02
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.TodayPass,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.EffCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.EffCnt):
            temEffList = tagSCDingjungeEff()
            _pos = temEffList.ReadData(_lpData, _pos)
            self.EffList.append(temEffList)
        self.SelectEffCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.SelectEffCnt):
            value,_pos=CommFunc.ReadDWORD(_lpData,_pos)
            self.SelectEffList.append(value)
        self.UnSelectCnt,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.SelectAuto,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.SelectSetCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.SelectSetCnt):
            value,_pos=CommFunc.ReadWORD(_lpData,_pos)
            self.SelectSetAttrIDList.append(value)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xB2
        self.Head.SubCmd = 0x02
        self.TodayPass = 0
        self.EffCnt = 0
        self.EffList = list()
        self.SelectEffCnt = 0
        self.SelectEffList = list()
        self.UnSelectCnt = 0
        self.SelectAuto = 0
        self.SelectSetCnt = 0
        self.SelectSetAttrIDList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 4
        length += 1
        for i in range(self.EffCnt):
            length += self.EffList[i].GetLength()
        length += 1
        length += 4 * self.SelectEffCnt
        length += 2
        length += 1
        length += 1
        length += 2 * self.SelectSetCnt
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteDWORD(data, self.TodayPass)
        data = CommFunc.WriteBYTE(data, self.EffCnt)
        for i in range(self.EffCnt):
            data = CommFunc.WriteString(data, self.EffList[i].GetLength(), self.EffList[i].GetBuffer())
        data = CommFunc.WriteBYTE(data, self.SelectEffCnt)
        for i in range(self.SelectEffCnt):
            data = CommFunc.WriteDWORD(data, self.SelectEffList[i])
        data = CommFunc.WriteWORD(data, self.UnSelectCnt)
        data = CommFunc.WriteBYTE(data, self.SelectAuto)
        data = CommFunc.WriteBYTE(data, self.SelectSetCnt)
        for i in range(self.SelectSetCnt):
            data = CommFunc.WriteWORD(data, self.SelectSetAttrIDList[i])
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                TodayPass:%d,
                                EffCnt:%d,
                                EffList:%s,
                                SelectEffCnt:%d,
                                SelectEffList:%s,
                                UnSelectCnt:%d,
                                SelectAuto:%d,
                                SelectSetCnt:%d,
                                SelectSetAttrIDList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.TodayPass,
                                self.EffCnt,
                                "...",
                                self.SelectEffCnt,
                                "...",
                                self.UnSelectCnt,
                                self.SelectAuto,
                                self.SelectSetCnt,
                                "..."
                                )
        return DumpString
m_NAtagSCDingjungeInfo=tagSCDingjungeInfo()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCDingjungeInfo.Head.Cmd,m_NAtagSCDingjungeInfo.Head.SubCmd))] = m_NAtagSCDingjungeInfo
#------------------------------------------------------
# B2 01 天子考验信息 #tagSCTianziKYInfo
class  tagSCTianziKYInfo(Structure):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Dingjunge.py
New file
@@ -0,0 +1,77 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.Dingjunge
#
# @todo:定军阁
# @author hxp
# @date 2026-01-06
# @version 1.0
#
# 详细描述: 定军阁
#
#-------------------------------------------------------------------------------
#"""Version = 2026-01-06 13:30"""
#-------------------------------------------------------------------------------
import FBCommon
import GameWorld
import IpyGameDataPY
import GameLogic_Dingjunge
import PlayerControl
import ChConfig
def OnExec(curPlayer, paramList):
    if not paramList:
        GameWorld.DebugAnswer(curPlayer, "定军阁进度: Dingjunge 今日关卡ID 历史关卡ID")
        GameWorld.DebugAnswer(curPlayer, "增加效果数: Dingjunge e 增加效果次数")
        GameWorld.DebugAnswer(curPlayer, "待选择效果: Dingjunge s 效果ID [效果ID ...]")
        return
    mapID = ChConfig.Def_FBMapID_Dingjunge
    value1 = paramList[0]
    if value1 == "e":
        addEffCnt = paramList[1] if len(paramList) > 1 else 1
        GameLogic_Dingjunge.GivePassLayerEff(curPlayer, addEffCnt)
    elif value1 == "s":
        setEffIDList = paramList[1:]
        sEffIDList = []
        for sIndex in range(IpyGameDataPY.GetFuncCfg("DingjungeEff", 3)):
            effID = setEffIDList[sIndex] if len(setEffIDList) > sIndex else 0
            if effID and not IpyGameDataPY.GetIpyGameDataNotLog("FBDJGEffect", effID):
                GameWorld.DebugAnswer(curPlayer, "效果ID不存在:%s" % effID)
                effID = 0
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGSelectEffect % sIndex, effID)
            sEffIDList.append(effID)
        GameWorld.DebugAnswer(curPlayer, "待选效果ID:%s" % sEffIDList)
    else:
        todayLineID = value1
        highestLineID = paramList[1] if len(paramList) > 1 else None
        if not highestLineID:
            highestLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBPassLineID % mapID)
        layerNum, levelNum = todayLineID / 100, todayLineID % 100
        ipyData = IpyGameDataPY.GetIpyGameDataNotLog("FBDJGLevel", layerNum, levelNum)
        if not ipyData:
            GameWorld.DebugAnswer(curPlayer, "不存在该层关卡:%s-%s" % (layerNum, levelNum))
            return
        if highestLineID:
            if todayLineID > highestLineID:
                highestLineID = todayLineID
            hLayerNum, hLevelNum = highestLineID / 100, highestLineID % 100
            if not IpyGameDataPY.GetIpyGameDataNotLog("FBDJGLevel", hLayerNum, hLevelNum):
                GameWorld.DebugAnswer(curPlayer, "不存在该层关:%s-%s" % (hLayerNum, hLevelNum))
                return
            GameWorld.DebugAnswer(curPlayer, "历史最高层关:%s-%s" % (hLayerNum, hLevelNum))
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FBPassLineID % mapID, highestLineID)
            FBCommon.Sync_FBPlayerFBInfoData(curPlayer, mapID)
        GameWorld.DebugAnswer(curPlayer, "今日层关:%s-%s" % (layerNum, levelNum))
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGLineID, todayLineID)
    GameLogic_Dingjunge.SyncDingjungeInfo(curPlayer)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
@@ -1549,10 +1549,12 @@
def OnPlayerFBQuickPass(curPlayer, mapID, lineID):
    '''副本快速过关验证
    @param mapID: 数据地图ID
    @param lineID: 目标关卡线路ID,可一次性跳多关,由前端发包决定
    @return: (bossID, quickCnt) 或  None
    @note: bossID 目标NPCID - 目标关卡所需要挑战的主NPCID,一般是boss,用于验证战力是否满足快速过关
    @note: quickCnt 本次总共跳过几关 - 默认1
    @param lineID: 目标关卡线路ID,可一次性跳多关,根据功能由前端发包决定或后端直接决定
    @return: (lineID, quickCnt, quickFightPower, quickData) 或  None
    @note: lineID 由后端决定的快速过关到哪,如果前端决定的则直接返回 lineID
    @note: quickCnt 本次总共跳过几关
    @note: quickFightPower 目标阵容战力,用于验证战力是否满足快速过关
    @note: quickData 扩展数据,功能自定义,传给 OnPlayerFBQuickPassResult
    '''
    do_FBLogic_ID = __GetFBLogic_MapID(mapID)
    
@@ -1564,7 +1566,7 @@
    
    return callFunc(curPlayer, mapID, lineID)
def OnPlayerFBQuickPassResult(curPlayer, mapID, lineID):
def OnPlayerFBQuickPassResult(curPlayer, mapID, lineID, quickData):
    '''副本快速过关结果
    '''
    do_FBLogic_ID = __GetFBLogic_MapID(mapID)
@@ -1574,7 +1576,7 @@
    if callFunc == None:
        return
    return callFunc(curPlayer, mapID, lineID)
    return callFunc(curPlayer, mapID, lineID, quickData)
#---------------------------------------------------------------------
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_Dingjunge.py
New file
@@ -0,0 +1,582 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GameWorldLogic.FBProcess.GameLogic_Dingjunge
#
# @todo:定军阁
# @author hxp
# @date 2026-01-06
# @version 1.0
#
# 详细描述: 定军阁
#
#-------------------------------------------------------------------------------
#"""Version = 2026-01-06 13:30"""
#-------------------------------------------------------------------------------
import FBCommon
import GameWorld
import ShareDefine
import PlayerControl
import PlayerBillboard
import ChPyNetSendPack
import ItemControler
import IpyGameDataPY
import NetPackCommon
import ChConfig
# 自动选择排序优先级索引
(
Priority_InSet, # 0
Priority_EffQuality, # 1
Priority_SetPriority, # 2
Priority_EIndex, # 3
Priority_EffInfo, # 4
Priority_EffID, # 5
Priority_AttrID, # 6
) = range(7)
def OnFBPlayerOnLogin(curPlayer):
    SyncDingjungeInfo(curPlayer)
    return
def OnFBPlayerOnDay(curPlayer):
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGLineID, 0)
    for eIndex in range(len(IpyGameDataPY.GetFuncEvalCfg("DingjungeEff", 1))):
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGEffect % eIndex, 0)
    for sIndex in range(IpyGameDataPY.GetFuncCfg("DingjungeEff", 3)):
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGSelectEffect % sIndex, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGUnSelectCnt, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGEffAuto, 0) # 每日重置自动开关
    SyncDingjungeInfo(curPlayer)
    return
def GetNextIpyData(curPlayer):
    ## 获取下一关ipyData
    todayLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGLineID)
    layerNum, levelNum = todayLineID / 100, todayLineID % 100
    if not layerNum:
        ipyData = IpyGameDataPY.GetIpyGameData("FBDJGLevel", 1, 1)
    elif not levelNum:
        ipyData = IpyGameDataPY.GetIpyGameData("FBDJGLevel", layerNum, 1)
    else:
        nextLayerNum = layerNum
        nextLevelNum = levelNum + 1 # 下一关
        ipyData = IpyGameDataPY.GetIpyGameDataNotLog("FBDJGLevel", nextLayerNum, nextLevelNum)
        if not ipyData:# 没有下一关取下一层
            nextLayerNum = layerNum + 1
            nextLevelNum = 1
            ipyData = IpyGameDataPY.GetIpyGameDataNotLog("FBDJGLevel", nextLayerNum, nextLevelNum)
    if ipyData:
        return ipyData
    GameWorld.DebugLog("已通关或找不到下一关数据! layerNum=%s,levelNum=%s" % (layerNum, levelNum))
    return
def GetPassLayerMax(curPlayer):
    ## 获取已通关的最大层级
    mapID = ChConfig.Def_FBMapID_Dingjunge
    highestLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBPassLineID % mapID)
    hLayerNum, hLevelNum = highestLineID / 100, highestLineID % 100
    passLayerMax = max(0, hLayerNum - 1) # 默认通关的是上一层
    # 如果过关记录在本层,且没有下一关了,也算通关了本层
    if hLayerNum and hLevelNum and not IpyGameDataPY.GetIpyGameDataNotLog("FBDJGLevel", hLayerNum, hLevelNum + 1):
        passLayerMax = hLayerNum
    return passLayerMax
def GetQuickStartLayer(curPlayer):
    ## 获取快速挑战的起始层级
    # @return: >1-可快速挑战的起始层级
    passLayerMax = GetPassLayerMax(curPlayer)
    backLayers = IpyGameDataPY.GetFuncCfg("Dingjunge", 1)
    quickStartLayer = passLayerMax + 1 - backLayers # 需要+1层
    if quickStartLayer > 1:
        return quickStartLayer
    return 0
def OnTurnFightRequest(curPlayer, mapID, funcLineID, tagType, tagID, valueList):
    ## 回合战斗请求
    highestLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBPassLineID % mapID)
    quickStartLayer = GetQuickStartLayer(curPlayer)
    if quickStartLayer:
        todayLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGLineID)
        if not todayLineID:
            GameWorld.DebugLog("今日还未快速战斗无法手动挑战! highestLineID=%s,quickStartLayer=%s" % (highestLineID, quickStartLayer))
            return
    nextIpyData = GetNextIpyData(curPlayer)
    if not nextIpyData:
        return
    layerNum = nextIpyData.GetLayerNum()
    levelNum = nextIpyData.GetLevelNum()
    funcLineID = layerNum * 100 + levelNum
    return True, funcLineID
def GetFBNPCLineupInfo(curPlayer, mapID, funcLineID):
    ## 获取NPC阵容相关
    # @return: npcLineupIDList, strongerLV, difficulty
    layerNum, levelNum = funcLineID / 100, funcLineID % 100
    ipyData = IpyGameDataPY.GetIpyGameData("FBDJGLevel", layerNum, levelNum)
    if not ipyData:
        return
    npcLineupIDList = ipyData.GetLineupIDList()
    strongerLV = ipyData.GetNPCLV()
    difficulty = ipyData.GetDifficulty()
    return npcLineupIDList, strongerLV, difficulty
def OnTurnFightAward(curPlayer, guid, mapID, funcLineID, winFaction, statMsg, dateStr, reqData, awardDict):
    ## 回合战斗结算奖励
    if not curPlayer:
        return
    isWin = winFaction == ChConfig.Def_FactionA
    if not isWin:
        return
    todayLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGLineID)
    GameWorld.DebugLog("定军阁结算: funcLineID=%s,todayLineID=%s" % (funcLineID, todayLineID))
    if todayLineID >= funcLineID:
        GameWorld.DebugLog("今日已过关的不重复结算奖励! todayLineID=%s >= %s" % (todayLineID, funcLineID))
        return
    layerNum, levelNum = funcLineID / 100, funcLineID % 100
    ipyData = IpyGameDataPY.GetIpyGameData("FBDJGLevel", layerNum, levelNum)
    if not ipyData:
        return
    awardItemList = []
    highestLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBPassLineID % mapID)
    # 首通
    if funcLineID > highestLineID:
        firstPassAwardList = ipyData.GetPassAwardList()
        awardItemList += firstPassAwardList
        GameWorld.DebugLog("首次过关: highestLineID=%s,firstPassAwardList=%s" % (highestLineID, firstPassAwardList))
        FBCommon.SetFBPass(curPlayer, mapID, funcLineID)
        PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_Dingjunge, funcLineID)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGLineID, funcLineID)
    awardItemList += ipyData.GetAwardList() # 挑战奖励
    GameWorld.DebugLog("最终奖励: mapID=%s,layerNum=%s,levelNum=%s,awardItemList=%s" % (mapID, layerNum, levelNum, awardItemList))
    awardDict.update({FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(awardItemList)})
    ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, event=["Dingjunge", False, {}], isNotifyAward=False)
    if not IpyGameDataPY.GetIpyGameDataNotLog("FBDJGLevel", layerNum, levelNum + 1):
        GameWorld.DebugLog("本层没有下一关了,通关本层!: layerNum=%s,levelNum=%s" % (layerNum, levelNum))
        GivePassLayerEff(curPlayer, 1)
    SyncDingjungeInfo(curPlayer)
    return
def OnPlayerFBQuickPass(curPlayer, mapID, lineID):
    '''副本快速过关验证
    @param mapID: 数据地图ID
    @param lineID: 目标关卡线路ID,可一次性跳多关,根据功能由前端发包决定或后端直接决定
    @return: (lineID, quickCnt, quickFightPower, quickData) 或  None
    @note: lineID 由后端决定的快速过关到哪,如果前端决定的则直接返回 lineID
    @note: quickCnt 本次总共跳过几关
    @note: quickFightPower 目标阵容战力,用于验证战力是否满足快速过关
    @note: quickData 扩展数据,功能自定义,传给 OnPlayerFBQuickPassResult
    '''
    todayLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGLineID)
    if todayLineID:
        GameWorld.DebugLog("今日已经在手动战斗了,无法快速挑战! todayLineID=%s" % (todayLineID))
        return
    highestLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBPassLineID % mapID)
    quickStartLayer = GetQuickStartLayer(curPlayer)
    if not quickStartLayer:
        GameWorld.DebugLog("还未达到可快速挑战的层级! highestLineID=%s" % (highestLineID))
        return
    quickData = [highestLineID, quickStartLayer]
    quickCnt = 0
    quickFightPower = 0
    return lineID, quickCnt, quickFightPower, quickData
def OnPlayerFBQuickPassResult(curPlayer, mapID, lineID, quickData):
    ## 副本快速过关结果
    highestLineID, quickStartLayer = quickData
    playerID = curPlayer.GetPlayerID()
    passLayerMax = GetPassLayerMax(curPlayer) # 历史最大过关层级
    todayLineID = quickStartLayer * 100 + 0 # 先设置已过到起始层第0关,前端如果有问题再设置为上一层最后一关
    GameWorld.DebugLog("定军阁快速战斗: highestLineID=%s,passLayerMax=%s,quickStartLayer=%s,todayLineID=%s"
                       % (highestLineID, passLayerMax, quickStartLayer, todayLineID), playerID)
    # 快速过关奖励按历史最大过关层级领取
    awardItemDict = {}
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for index in range(ipyDataMgr.GetFBDJGQuickCount()):
        quickIpyData = ipyDataMgr.GetFBDJGQuickByIndex(index)
        needLayer = quickIpyData.GetNeedLayer()
        if needLayer > passLayerMax:
            break
        quickItemList = quickIpyData.GetQuickAwardList()
        for itemInfo in quickItemList:
            itemID, itemCount = itemInfo[:2]
            awardItemDict[itemID] = awardItemDict.get(itemID, 0) + itemCount
    awardItemList = [[itemID, itemCount] for itemID, itemCount in awardItemDict.items()]
    # 设置起始层关卡
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGLineID, todayLineID)
    addEffCnt = quickStartLayer - 1 # -1是代表加成效果结算到起始的上一层,每过1层+1次
    GivePassLayerEff(curPlayer, addEffCnt)
    SyncDingjungeInfo(curPlayer)
    ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, event=["Dingjunge", False, {}])
    return
def GivePassLayerEff(curPlayer, addEffCnt=1):
    unSelectCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGUnSelectCnt) + addEffCnt
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGUnSelectCnt, unSelectCnt)
    GameWorld.DebugLog("增加效果加成次数: addEffCnt=%s,unSelectCnt=%s" % (addEffCnt, unSelectCnt))
    if not __doAutoSelectAll(curPlayer):
        __randSelectEff(curPlayer)
    return
#// B1 01 定军阁效果预设 #tagCSDingjungeEffSet
#
#struct    tagCSDingjungeEffSet
#{
#    tagHead         Head;
#    BYTE        SelectAuto;    //是否启用自动选择
#    BYTE        SelectSetCnt;
#    WORD        SelectSetAttrIDList[SelectSetCnt];    //预设优先选择属性ID列表 [优先级1属性ID, ...]
#};
def OnDingjungeEffSet(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    selectAuto = 1 if clientData.SelectAuto else 0
    selectSetAttrIDList = clientData.SelectSetAttrIDList
    canSetAttrIDList = []
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for index in range(ipyDataMgr.GetFBDJGEffectCount()):
        ipyData = ipyDataMgr.GetFBDJGEffectByIndex(index)
        attrID = ipyData.GetAttrID()
        if attrID not in canSetAttrIDList:
            canSetAttrIDList.append(attrID)
    canSetAttrIDList.sort()
    GameWorld.DebugLog("效果预设: selectAuto=%s,selectSetAttrIDList=%s,canSetAttrIDList=%s" % (selectAuto, selectSetAttrIDList, canSetAttrIDList))
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGEffAuto, selectAuto)
    for ssIndex in range(IpyGameDataPY.GetFuncCfg("DingjungeEff", 4)):
        attrID = selectSetAttrIDList[ssIndex] if len(selectSetAttrIDList) > ssIndex else 0
        if attrID not in canSetAttrIDList:
            attrID = 0
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGEffSet % ssIndex, attrID)
    SyncDingjungeInfo(curPlayer)
    return
#// B1 02 定军阁效果选择 #tagCSDingjungeEffSelect
#
#struct    tagCSDingjungeEffSelect
#{
#    tagHead         Head;
#    BYTE        SelectType;    //0-手动选择,1-放弃本次选择,2-一键选择(仅开启了自动选择时有效)
#    BYTE        SelectIndex;    //手动选择索引 0~n
#    BYTE        ReplaceHole;    //手动选择替换槽位 1~n,槽位=槽索引+1,升级时可直接发0
#};
def OnDingjungeEffSelect(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    selectType = clientData.SelectType
    selectIndex = clientData.SelectIndex
    replaceHole = clientData.ReplaceHole
    if selectType == 2:
        __doAutoSelectAll(curPlayer)
    elif selectType == 1:
        __randSelectEff(curPlayer, isReset=True)
    else:
        if __doSelectEff(curPlayer, selectIndex, replaceHole):
            __randSelectEff(curPlayer, isReset=True)
    SyncDingjungeInfo(curPlayer)
    return
def __doAutoSelectAll(curPlayer):
    if not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGEffAuto):
        GameWorld.DebugLog("未开启自动选择!")
        return
    unSelectCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGUnSelectCnt)
    selectSetAttrIDList = [] # 效果选择预设
    for ssIndex in range(IpyGameDataPY.GetFuncCfg("DingjungeEff", 4)):
        attrID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGEffSet % ssIndex)
        if attrID:
            selectSetAttrIDList.append(attrID)
    effHoleCnt = __getUnlockEffHoleCnt(curPlayer)
    GameWorld.DebugLog("执行一键选择加成效果: unSelectCnt=%s,effHoleCnt=%s,selectSetAttrIDList=%s" % (unSelectCnt, effHoleCnt, selectSetAttrIDList))
    randEffCnt = IpyGameDataPY.GetFuncCfg("DingjungeEff", 3)
    for _ in range(unSelectCnt):
        effIDList = __randSelectEff(curPlayer, randEffCnt)
        if not effIDList:
            break
        if not __doAutoSelectEff(curPlayer, effIDList, selectSetAttrIDList, effHoleCnt):
            # 不需要自动选择,直接退出,玩家手动选择
            break
        # 自动选择后重置
        for sIndex in range(randEffCnt):
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGSelectEffect % sIndex, 0)
    return True
def __getUnlockEffHoleCnt(curPlayer):
    ## 获取已解锁的效果槽数
    todayLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGLineID)
    effHoleNeedLVIDList = IpyGameDataPY.GetFuncEvalCfg("DingjungeEff", 1)
    effHoleCnt = 0 # 已解锁的效果槽数
    for needLVID in effHoleNeedLVIDList:
        if todayLineID >= needLVID:
            effHoleCnt += 1
    return effHoleCnt
def __randSelectEff(curPlayer, randEffCnt=0, isReset=False):
    ## 随机生成待选择加成效果
    unSelectCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGUnSelectCnt)
    if unSelectCnt <= 0:
        GameWorld.DebugLog("没有未处理的加成效果次数了")
        return
    if not randEffCnt:
        randEffCnt = IpyGameDataPY.GetFuncCfg("DingjungeEff", 3)
    effIDList = []
    if isReset:
        # 重置
        for sIndex in range(randEffCnt):
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGSelectEffect % sIndex, 0)
    else:
        for sIndex in range(randEffCnt):
            effID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGSelectEffect % sIndex)
            if not effID:
                break
            effIDList.append(effID)
    if effIDList:
        GameWorld.DebugLog("已存在未选择的加成效果等选择后再生成: effIDList=%s,unSelectCnt=%s" % (effIDList, unSelectCnt))
        return effIDList
    fullLVEffIDList = [] # 已满级的效果ID列表
    effMaxLV = IpyGameDataPY.GetFuncCfg("DingjungeEff", 2)
    for eIndex in range(len(IpyGameDataPY.GetFuncEvalCfg("DingjungeEff", 1))):
        effInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGEffect % eIndex)
        if not effInfo:
            break
        effID, effLV = effInfo / 100, effInfo % 100
        if effLV >= effMaxLV:
            fullLVEffIDList.append(effID)
    randWeightList = []
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for index in range(ipyDataMgr.GetFBDJGEffectCount()):
        ipyData = ipyDataMgr.GetFBDJGEffectByIndex(index)
        effID = ipyData.GetEffID()
        if effID in fullLVEffIDList:
            # 排除满级的
            continue
        randWeight = ipyData.GetRandWeight()
        if randWeight:
            randWeightList.append([randWeight, effID])
    # 随机效果,不重复
    randCnt = 200
    while len(effIDList) < randEffCnt and randCnt > 0:
        randCnt -= 1
        randEffID = GameWorld.GetResultByWeightList(randWeightList)
        if randEffID not in effIDList:
            effIDList.append(randEffID)
    unSelectCnt -= 1
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGUnSelectCnt, unSelectCnt)
    for sIndex in range(randEffCnt):
        effID = effIDList[sIndex] if len(effIDList) > sIndex else 0
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGSelectEffect % sIndex, effID)
    #GameWorld.DebugLog("随机生成加成效果: effIDList=%s,unSelectCnt=%s,fullLVEffIDList=%s" % (effIDList, unSelectCnt, fullLVEffIDList))
    return effIDList
def __doAutoSelectEff(curPlayer, selectEffIDList, selectSetAttrIDList, effHoleCnt):
    ## 自动选择加成
    # 若随机出了多种预设内的的属性,则优先选择品质高的,只出现单种预设内属性的话,则预设优先
    priorityEffList = [] # 品质优先
    for effID in selectEffIDList:
        effIpyData = IpyGameDataPY.GetIpyGameData("FBDJGEffect", effID)
        if not effIpyData:
            continue
        effQuality = effIpyData.GetEffQuality()
        attrID = effIpyData.GetAttrID()
        inSet = 0 # 预设优先,但多个预设同时出现时,先品质优先,再预设优先级
        setPriority = 0 # 预设排序优先级
        if attrID in selectSetAttrIDList:
            inSet = 1
            setPriority = len(selectSetAttrIDList) - selectSetAttrIDList.index(attrID)
        effLV = 1 # 初始1级
        effInfo = effID * 100 + effLV
        eIndex = -1 # 生效索引,设为-1,比已生效的低
        priorityEffList.append([inSet, effQuality, setPriority, eIndex, effInfo, effID, attrID])
    priorityEffList.sort(reverse=True)
    if not priorityEffList:
        return
    #GameWorld.DebugLog("    排序优先级: [inSet, effQuality, setPriority, eIndex, effInfo, effID, attrID]")
    #GameWorld.DebugLog("    待选择排序: %s" % priorityEffList)
    selectEff = priorityEffList[0] # 自动选择第一个
    #selectAttrID = selectEff[Priority_AttrID]
    selectEffID = selectEff[Priority_EffID]
    selectEffInfo = selectEff[Priority_EffInfo]
    effMaxLV = IpyGameDataPY.GetFuncCfg("DingjungeEff", 2)
    emptyIndex = -1
    effList = [] # 已生效的效果
    for eIndex in range(effHoleCnt):
        effInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGEffect % eIndex)
        if not effInfo:
            if emptyIndex == -1:
                #GameWorld.DebugLog("    还有空槽: eIndex=%s" % eIndex)
                emptyIndex = eIndex
            continue
        effID, effLV = effInfo / 100, effInfo % 100
        effIpyData = IpyGameDataPY.GetIpyGameData("FBDJGEffect", effID)
        if not effIpyData:
            continue
        effQuality = effIpyData.GetEffQuality()
        attrID = effIpyData.GetAttrID()
        # 已存在,升级
        if effID == selectEffID and effLV < effMaxLV:
            effLV += 1
            effInfo = effID * 100 + effLV
            #GameWorld.DebugLog("    已存在该效果直接升级: eIndex=%s,effID=%s,effLV=%s,attrID=%s" % (eIndex, effID, effLV, attrID))
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGEffect % eIndex, effInfo)
            return True
        inSet = 0 # 预设优先,但多个预设同时出现时,先品质优先,再预设优先级
        setPriority = 0 # 预设排序优先级
        if attrID in selectSetAttrIDList:
            inSet = 1
            setPriority = len(selectSetAttrIDList) - selectSetAttrIDList.index(attrID)
        effList.append([inSet, effQuality, setPriority, eIndex, effInfo, effID, attrID])
    # 空槽
    if emptyIndex != -1:
        eIndex = emptyIndex
        effID = selectEffID
        effLV = 1
        effInfo = effID * 100 + effLV
        #GameWorld.DebugLog("    空槽直接设置: emptyIndex=%s,effID=%s,effLV=%s,attrID=%s,effList=%s" % (eIndex, effID, effLV, selectAttrID, effList))
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGEffect % eIndex, effInfo)
        return True
    # 替换逻辑
    effList.append(selectEff) # 选择项再与生效的一起排序
    effList.sort(reverse=True)
    lastEff = effList[-1]
    lastEIndex = lastEff[Priority_EIndex]
    #lastEffID = lastEff[Priority_EffID]
    #lastAttrID = lastEff[Priority_AttrID]
    if lastEIndex == -1:
        pass
        #GameWorld.DebugLog("    优先级比已生效的低,直接舍弃! lastEIndex=%s,lastEffID=%s,lastAttrID=%s,effList=%s" % (lastEIndex, lastEffID, lastAttrID, effList))
    else:
        replaceIndex = lastEIndex
        effInfo = selectEffInfo
        #GameWorld.DebugLog("    优先级比已生效的高,直接替换! replaceIndex=%s,selectAttrID=%s,effInfo=%s,effList=%s" % (replaceIndex, selectAttrID, effInfo, effList))
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGEffect % replaceIndex, effInfo)
    return True
def __doSelectEff(curPlayer, selectIndex, replaceHole):
    ## 手动选择效果
    selectEffID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGSelectEffect % selectIndex)
    GameWorld.DebugLog("手动选择效果: selectIndex=%s,selectEffID=%s,replaceHole=%s" % (selectIndex, selectEffID, replaceHole))
    if not selectEffID:
        return
    effHoleCnt = __getUnlockEffHoleCnt(curPlayer)
    effMaxLV = IpyGameDataPY.GetFuncCfg("DingjungeEff", 2)
    emptyIndex = -1
    for eIndex in range(effHoleCnt):
        effInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGEffect % eIndex)
        if not effInfo:
            if emptyIndex == -1:
                GameWorld.DebugLog("    还有空槽: eIndex=%s" % eIndex)
                emptyIndex = eIndex
            continue
        effID, effLV = effInfo / 100, effInfo % 100
        # 已存在,升级
        if effID == selectEffID:
            if effLV >= effMaxLV:
                GameWorld.DebugLog("    已存在该效果且已满级: eIndex=%s,effID=%s,effLV=%s" % (eIndex, effID, effLV))
                return
            effLV += 1
            effInfo = effID * 100 + effLV
            GameWorld.DebugLog("    已存在该效果直接升级: eIndex=%s,effID=%s,effLV=%s" % (eIndex, effID, effLV))
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGEffect % eIndex, effInfo)
            return True
    # 空槽
    if emptyIndex != -1:
        eIndex = emptyIndex
        effID = selectEffID
        effLV = 1
        effInfo = effID * 100 + effLV
        GameWorld.DebugLog("    空槽直接设置: emptyIndex=%s,effID=%s,effLV=%s" % (eIndex, effID, effLV))
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGEffect % eIndex, effInfo)
        return True
    # 替换逻辑
    if replaceHole < 1 or replaceHole > effHoleCnt:
        GameWorld.DebugLog("    替换的目标槽位不可用: replaceHole=%s,effHoleCnt=%s" % (replaceHole, effHoleCnt))
        return
    effLV = 1
    selectEffInfo = selectEffID * 100 + effLV
    replaceIndex = replaceHole - 1
    effInfo = selectEffInfo
    GameWorld.DebugLog("    手动选择替换! replaceIndex=%s,effInfo=%s" % (replaceIndex, effInfo))
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DJGEffect % replaceIndex, effInfo)
    return True
def SyncDingjungeInfo(curPlayer):
    clientPack = ChPyNetSendPack.tagSCDingjungeInfo()
    clientPack.TodayPass = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGLineID)
    effList = [] # 已生效的效果
    for eIndex in range(len(IpyGameDataPY.GetFuncEvalCfg("DingjungeEff", 1))):
        effInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGEffect % eIndex)
        if not effInfo:
            break
        effID, effLV = effInfo / 100, effInfo % 100
        eff = ChPyNetSendPack.tagSCDingjungeEff()
        eff.EffIndex = eIndex
        eff.EffID = effID
        eff.EffLV = effLV
        effList.append(eff)
    clientPack.EffList = effList
    clientPack.EffCnt = len(clientPack.EffList)
    selectEffList = [] # 待选择的效果
    for sIndex in range(IpyGameDataPY.GetFuncCfg("DingjungeEff", 3)):
        effID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGSelectEffect % sIndex)
        if not effID:
            break
        selectEffList.append(effID)
    clientPack.SelectEffList = selectEffList
    clientPack.SelectEffCnt = len(clientPack.SelectEffList)
    clientPack.UnSelectCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGUnSelectCnt)
    clientPack.SelectAuto = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGEffAuto)
    selectSetAttrIDList = [] # 效果选择预设
    for ssIndex in range(IpyGameDataPY.GetFuncCfg("DingjungeEff", 4)):
        attrID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DJGEffSet % ssIndex)
        selectSetAttrIDList.append(attrID)
    clientPack.SelectSetAttrIDList = selectSetAttrIDList
    clientPack.SelectSetCnt = len(clientPack.SelectSetAttrIDList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -964,6 +964,29 @@
                        ("list", "RandWeightItemList", 0),
                        ),
                "FBDJGLevel":(
                        ("WORD", "LayerNum", 1),
                        ("BYTE", "LevelNum", 1),
                        ("list", "PassAwardList", 0),
                        ("list", "AwardList", 0),
                        ("list", "LineupIDList", 0),
                        ("WORD", "NPCLV", 0),
                        ("float", "Difficulty", 0),
                        ),
                "FBDJGQuick":(
                        ("WORD", "NeedLayer", 1),
                        ("list", "QuickAwardList", 0),
                        ),
                "FBDJGEffect":(
                        ("DWORD", "EffID", 1),
                        ("BYTE", "EffQuality", 0),
                        ("BYTE", "AttrID", 0),
                        ("DWORD", "AttrValue", 0),
                        ("DWORD", "RandWeight", 0),
                        ),
                "ADAward":(
                        ("DWORD", "ADID", 1),
                        ("BYTE", "ADCntMax", 0),
@@ -3584,6 +3607,44 @@
    def GetOtherAttrDict(self): return self.attrTuple[5] # 其他属性 {attrID:attrValue, ...} dict
    def GetRandWeightItemList(self): return self.attrTuple[6] # 宝箱随机物品权重列表,[[权重,物品ID,数量], ...] list
# 定军阁关卡表
class IPY_FBDJGLevel():
    def __init__(self):
        self.attrTuple = None
        return
    def GetLayerNum(self): return self.attrTuple[0] # 层数 WORD
    def GetLevelNum(self): return self.attrTuple[1] # 关卡编号 BYTE
    def GetPassAwardList(self): return self.attrTuple[2] #  过关奖励列表,[[物品ID,个数], ...] list
    def GetAwardList(self): return self.attrTuple[3] #  挑战奖励,[[物品ID,个数], ...] list
    def GetLineupIDList(self): return self.attrTuple[4] #  阵容ID列表,小队1阵容ID|小队2阵容ID|... list
    def GetNPCLV(self): return self.attrTuple[5] # NPC等级 WORD
    def GetDifficulty(self): return self.attrTuple[6] # 难度系数 float
# 定军阁速战奖励表
class IPY_FBDJGQuick():
    def __init__(self):
        self.attrTuple = None
        return
    def GetNeedLayer(self): return self.attrTuple[0] # 所需层数 WORD
    def GetQuickAwardList(self): return self.attrTuple[1] #  速战奖励列表,[[物品ID,个数], ...] list
# 定军阁效果表
class IPY_FBDJGEffect():
    def __init__(self):
        self.attrTuple = None
        return
    def GetEffID(self): return self.attrTuple[0] # 效果ID DWORD
    def GetEffQuality(self): return self.attrTuple[1] #  效果品质 BYTE
    def GetAttrID(self): return self.attrTuple[2] #  属性ID BYTE
    def GetAttrValue(self): return self.attrTuple[3] #  属性值 DWORD
    def GetRandWeight(self): return self.attrTuple[4] #  随机权重 DWORD
# 广告奖励表
class IPY_ADAward():
    
@@ -5674,6 +5735,9 @@
        self.__LoadFileData("FBFunc", onlyCheck)
        self.__LoadFileData("FBLine", onlyCheck)
        self.__LoadFileData("Tianzi", onlyCheck)
        self.__LoadFileData("FBDJGLevel", onlyCheck)
        self.__LoadFileData("FBDJGQuick", onlyCheck)
        self.__LoadFileData("FBDJGEffect", onlyCheck)
        self.__LoadFileData("ADAward", onlyCheck)
        self.__LoadFileData("Success", onlyCheck)
        self.__LoadFileData("TongTianLV", onlyCheck)
@@ -6632,6 +6696,27 @@
        self.CheckLoadData("Tianzi")
        return self.ipyTianziCache[index]
    def GetFBDJGLevelCount(self):
        self.CheckLoadData("FBDJGLevel")
        return self.ipyFBDJGLevelLen
    def GetFBDJGLevelByIndex(self, index):
        self.CheckLoadData("FBDJGLevel")
        return self.ipyFBDJGLevelCache[index]
    def GetFBDJGQuickCount(self):
        self.CheckLoadData("FBDJGQuick")
        return self.ipyFBDJGQuickLen
    def GetFBDJGQuickByIndex(self, index):
        self.CheckLoadData("FBDJGQuick")
        return self.ipyFBDJGQuickCache[index]
    def GetFBDJGEffectCount(self):
        self.CheckLoadData("FBDJGEffect")
        return self.ipyFBDJGEffectLen
    def GetFBDJGEffectByIndex(self, index):
        self.CheckLoadData("FBDJGEffect")
        return self.ipyFBDJGEffectCache[index]
    def GetADAwardCount(self):
        self.CheckLoadData("ADAward")
        return self.ipyADAwardLen
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFB.py
@@ -29,7 +29,6 @@
import FBLogic
import IpyGameDataPY
import ShareDefine
import NPCCommon
import ChConfig
#---------------------------------------------------------------------
@@ -120,21 +119,20 @@
        return
    
    reqRet = FBLogic.OnPlayerFBQuickPass(curPlayer, mapID, lineID)
    if not reqRet or len(reqRet) != 2:
    if not reqRet:
        GameWorld.DebugLog("无法一键过关副本: mapID=%s,lineID=%s" % (mapID, lineID), playerID)
        return
    bossID, quickCnt = reqRet
    if bossID:
        npcData = GameWorld.GetGameData().FindNPCDataByID(bossID)
        if not npcData:
            return
        npcFightPower = NPCCommon.GetSuppressFightPower(npcData)
    lineID = reqRet[0]
    quickCnt = reqRet[1] if len(reqRet) > 1 else 0
    quickFightPower = reqRet[2] if len(reqRet) > 2 else 0
    quickData = reqRet[3] if len(reqRet) > 3 else []
    if quickFightPower:
        quickNeedRatio = IpyGameDataPY.GetFuncCfg("FBQuickPass", 1)
        quickNeedFightPower = int(npcFightPower * quickNeedRatio)
        quickNeedFightPower = int(quickFightPower * quickNeedRatio)
        curFightPower = PlayerControl.GetFightPower(curPlayer)
        if quickNeedFightPower and curFightPower < quickNeedFightPower:
            GameWorld.DebugLog("无法一键过关副本! 战力限制: mapID=%s,lineID=%s,bossID=%s,npcFightPower=%s,quickNeedFightPower=%s > %s"
                               % (mapID, lineID, bossID, npcFightPower, quickNeedFightPower, curFightPower), playerID)
            GameWorld.DebugLog("无法一键过关副本! 战力限制: mapID=%s,lineID=%s,quickFightPower=%s,quickNeedFightPower=%s > %s"
                               % (mapID, lineID, quickFightPower, quickNeedFightPower, curFightPower), playerID)
            PlayerControl.NotifyCode(curPlayer, 'TaskFeedback4')
            return
        
@@ -146,6 +144,6 @@
        FBCommon.AddEnterFBCount(curPlayer, mapID, quickCnt)
        
    #扫荡结果给奖励等
    FBLogic.OnPlayerFBQuickPassResult(curPlayer, mapID, lineID)
    FBLogic.OnPlayerFBQuickPassResult(curPlayer, mapID, lineID, quickData)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -433,7 +433,8 @@
Def_BT_Tianzi,    # 天子考验伤害榜 2
Def_BT_OSA_MainLevel,    # 开服关卡榜 3
Def_BT_OSA_HeroCall,    # 开服招募榜 4
) = range(0, 5)
Def_BT_Dingjunge,    # 定军阁过关榜 5
) = range(0, 6)
''' 跨服排行榜类型, 从 150 开始,最大条数在功能配置表 CrossBillboardSet 配置,没配默认100
与本服榜单存储的是不一样的数据库表格,理论上类型可以和本服榜单类型重复,为了做下区分防误导,跨服榜单从 150 开始
@@ -447,7 +448,7 @@
BillboardTypeAllList = BillboardTypeList + CrossBillboardTypeList
BillboardNameDict = {Def_BT_MainLevel:"主线过关榜", Def_BT_Arena:"演武场积分周榜", Def_BT_Tianzi:"天子考验伤害榜", 
                     Def_BT_OSA_MainLevel:"开服关卡榜", Def_BT_OSA_HeroCall:"开服招募榜"}
                     Def_BT_OSA_MainLevel:"开服关卡榜", Def_BT_OSA_HeroCall:"开服招募榜", Def_BT_Dingjunge:"定军阁过关榜"}
#仙盟榜单类型
FamilyBillboardList = []