hxp
2025-01-09 c5731326acc36a3cfc6870ddb51ce2cc86e2cdc5
10361 【越南】【英语】【BT】【砍树】仙匠大会 - 服务端
20个文件已修改
3个文件已添加
2232 ■■■■■ 已修改文件
PySysDB/PySysDBG.h 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py 428 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerActLianqi.py 264 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py 428 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Lianqi.py 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActLianqi.py 635 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerZhanling.py 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBG.h
@@ -754,6 +754,32 @@
    WORD        XiangongID;    //晋升仙宫ID
};
//炼器活动跨服表
struct tagCrossActLianqi
{
    DWORD        _CfgID;    //配置ID
    char        ActGroupName;    //活动组名(同组活动的名字需相同)
    BYTE        ZoneID;        //组内分组编号
    list        ServerIDRangeList;    //活动的账号服务器ID范围列表 [[serverIDA, serverIDB], ...]
    char        StartDate;    //开启日期
    char        EndDate;    //结束日期
    char        JoinStartTime;    //参与开始时间点
    char        JoinEndTime;    //参与结束时间点
    WORD        LVLimit;    //限制等级
    WORD        PersonalTemplateID;    //个人排行模板编号
};
//炼器榜单模版表
struct tagActLianqiBillTemp
{
    DWORD        _TemplateID;    //模板编号
    BYTE        Rank;    //名次
    list        AwardItemList;    //奖励物品列表[[物品ID,个数,是否拍品], ...]
    DWORD        NeedScore;    //上榜所需积分
};
//仙匣秘境活动时间表
struct tagActXianXiaMJ
PySysDB/PySysDBPY.h
@@ -2034,6 +2034,16 @@
    dict        ScoreAwardEx;    //达标积分额外奖励 {积分:[[物品ID,个数,是否拍品], ...], ...}
};
//炼器榜单模版表
struct tagActLianqiBillTemp
{
    DWORD        _TemplateID;    //模板编号
    BYTE        Rank;    //名次
    list        AwardItemList;    //奖励物品列表[[物品ID,个数,是否拍品], ...]
    DWORD        NeedScore;    //上榜所需积分
};
//仙匣秘境活动时间表
struct tagActXianXiaMJ
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -16711,6 +16711,70 @@
#------------------------------------------------------
# AA 25 炼器操作 #tagCMActLianqiOP
class  tagCMActLianqiOP(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("OPType", c_ubyte),    # 1-移动;2-使用道具;3-重新开始;4-领取等级奖励
                  ("OPValue", c_int),    # 移动时-发1上2下3左4右;使用道具时-发使用个数*10+道具ID所在配置索引;等级奖励时-发领取的奖励等级
                  ("OPValue2", c_int),    # 使用道具时-发选中格子A的行列值 行*10+列
                  ("OPValue3", c_int),    # 使用道具时-发选中格子B的行列值 行*10+列
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xAA
        self.SubCmd = 0x25
        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 = 0xAA
        self.SubCmd = 0x25
        self.OPType = 0
        self.OPValue = 0
        self.OPValue2 = 0
        self.OPValue3 = 0
        return
    def GetLength(self):
        return sizeof(tagCMActLianqiOP)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// AA 25 炼器操作 //tagCMActLianqiOP:
                                Cmd:%s,
                                SubCmd:%s,
                                OPType:%d,
                                OPValue:%d,
                                OPValue2:%d,
                                OPValue3:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.OPType,
                                self.OPValue,
                                self.OPValue2,
                                self.OPValue3
                                )
        return DumpString
m_NAtagCMActLianqiOP=tagCMActLianqiOP()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMActLianqiOP.Cmd,m_NAtagCMActLianqiOP.SubCmd))] = m_NAtagCMActLianqiOP
#------------------------------------------------------
# AA 12 选择转盘活动物品 #tagCMActTurntableChooseItem
class  tagCMActTurntableChooseItem(Structure):
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
@@ -44354,6 +44354,434 @@
#------------------------------------------------------
# AA 90 炼器跨服活动信息 #tagMCCrossActLianqiInfo
class  tagMCCrossActLianqiItem(Structure):
    _pack_ = 1
    _fields_ = [
                  ("ItemID", c_int),
                  ("ItemCount", c_ushort),
                  ("IsBind", 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.ItemID = 0
        self.ItemCount = 0
        self.IsBind = 0
        return
    def GetLength(self):
        return sizeof(tagMCCrossActLianqiItem)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// AA 90 炼器跨服活动信息 //tagMCCrossActLianqiInfo:
                                ItemID:%d,
                                ItemCount:%d,
                                IsBind:%d
                                '''\
                                %(
                                self.ItemID,
                                self.ItemCount,
                                self.IsBind
                                )
        return DumpString
class  tagMCCrossActLianqiBillard(Structure):
    Rank = 0    #(DWORD Rank)// 名次,1-代表第一名;支持夸段,如1,3 代表第1名,第2~3名
    Count = 0    #(BYTE Count)// 奖励物品数
    AwardItemList = list()    #(vector<tagMCCrossActLianqiItem> AwardItemList)// 奖励物品列表
    NeedScore = 0    #(DWORD NeedScore)// 上榜所需积分
    data = None
    def __init__(self):
        self.Clear()
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        self.Rank,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.Count):
            temAwardItemList = tagMCCrossActLianqiItem()
            _pos = temAwardItemList.ReadData(_lpData, _pos)
            self.AwardItemList.append(temAwardItemList)
        self.NeedScore,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        return _pos
    def Clear(self):
        self.Rank = 0
        self.Count = 0
        self.AwardItemList = list()
        self.NeedScore = 0
        return
    def GetLength(self):
        length = 0
        length += 4
        length += 1
        for i in range(self.Count):
            length += self.AwardItemList[i].GetLength()
        length += 4
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteDWORD(data, self.Rank)
        data = CommFunc.WriteBYTE(data, self.Count)
        for i in range(self.Count):
            data = CommFunc.WriteString(data, self.AwardItemList[i].GetLength(), self.AwardItemList[i].GetBuffer())
        data = CommFunc.WriteDWORD(data, self.NeedScore)
        return data
    def OutputString(self):
        DumpString = '''
                                Rank:%d,
                                Count:%d,
                                AwardItemList:%s,
                                NeedScore:%d
                                '''\
                                %(
                                self.Rank,
                                self.Count,
                                "...",
                                self.NeedScore
                                )
        return DumpString
class  tagMCCrossActLianqiInfo(Structure):
    Head = tagHead()
    ServerInfoLen = 0    #(BYTE ServerInfoLen)
    ServerIDRangeInfo = ""    #(String ServerIDRangeInfo)//开放该活动的服务器ID范围列表,json格式 [[IDA, IDB], ...], [] 为全服
    GroupValue1 = 0    #(BYTE GroupValue1)// 活动榜单分组值1,用于查询对应榜单
    StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
    EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
    JoinStartTime = ""    #(char JoinStartTime[5])// 参与开始时间点 mm:ss
    JoinEndTime = ""    #(char JoinEndTime[5])// 参与结束时间点 mm:ss
    LimitLV = 0    #(WORD LimitLV)// 限制等级
    PersonalBillCount = 0    #(BYTE PersonalBillCount)
    PersonalBillboardInfoList = list()    #(vector<tagMCCrossActLianqiBillard> PersonalBillboardInfoList)// 个人榜单奖励信息列表,如果没有代表本次活动没有该榜奖励
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xAA
        self.Head.SubCmd = 0x90
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.ServerInfoLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.ServerIDRangeInfo,_pos = CommFunc.ReadString(_lpData, _pos,self.ServerInfoLen)
        self.GroupValue1,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
        self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
        self.JoinStartTime,_pos = CommFunc.ReadString(_lpData, _pos,5)
        self.JoinEndTime,_pos = CommFunc.ReadString(_lpData, _pos,5)
        self.LimitLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.PersonalBillCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.PersonalBillCount):
            temPersonalBillboardInfoList = tagMCCrossActLianqiBillard()
            _pos = temPersonalBillboardInfoList.ReadData(_lpData, _pos)
            self.PersonalBillboardInfoList.append(temPersonalBillboardInfoList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xAA
        self.Head.SubCmd = 0x90
        self.ServerInfoLen = 0
        self.ServerIDRangeInfo = ""
        self.GroupValue1 = 0
        self.StartDate = ""
        self.EndtDate = ""
        self.JoinStartTime = ""
        self.JoinEndTime = ""
        self.LimitLV = 0
        self.PersonalBillCount = 0
        self.PersonalBillboardInfoList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += len(self.ServerIDRangeInfo)
        length += 1
        length += 10
        length += 10
        length += 5
        length += 5
        length += 2
        length += 1
        for i in range(self.PersonalBillCount):
            length += self.PersonalBillboardInfoList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.ServerInfoLen)
        data = CommFunc.WriteString(data, self.ServerInfoLen, self.ServerIDRangeInfo)
        data = CommFunc.WriteBYTE(data, self.GroupValue1)
        data = CommFunc.WriteString(data, 10, self.StartDate)
        data = CommFunc.WriteString(data, 10, self.EndtDate)
        data = CommFunc.WriteString(data, 5, self.JoinStartTime)
        data = CommFunc.WriteString(data, 5, self.JoinEndTime)
        data = CommFunc.WriteWORD(data, self.LimitLV)
        data = CommFunc.WriteBYTE(data, self.PersonalBillCount)
        for i in range(self.PersonalBillCount):
            data = CommFunc.WriteString(data, self.PersonalBillboardInfoList[i].GetLength(), self.PersonalBillboardInfoList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                ServerInfoLen:%d,
                                ServerIDRangeInfo:%s,
                                GroupValue1:%d,
                                StartDate:%s,
                                EndtDate:%s,
                                JoinStartTime:%s,
                                JoinEndTime:%s,
                                LimitLV:%d,
                                PersonalBillCount:%d,
                                PersonalBillboardInfoList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.ServerInfoLen,
                                self.ServerIDRangeInfo,
                                self.GroupValue1,
                                self.StartDate,
                                self.EndtDate,
                                self.JoinStartTime,
                                self.JoinEndTime,
                                self.LimitLV,
                                self.PersonalBillCount,
                                "..."
                                )
        return DumpString
m_NAtagMCCrossActLianqiInfo=tagMCCrossActLianqiInfo()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCCrossActLianqiInfo.Head.Cmd,m_NAtagMCCrossActLianqiInfo.Head.SubCmd))] = m_NAtagMCCrossActLianqiInfo
#------------------------------------------------------
# AA 91 炼器活动玩家信息 #tagMCActLianqiPlayerInfo
class  tagMCActLianqiTileMove(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Row", c_ubyte),    # 行,0为第1行
                  ("Col", c_ubyte),    # 列,0为第1列
                  ("ToRow", c_ubyte),    # 移动到目标行
                  ("ToCol", 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.Row = 0
        self.Col = 0
        self.ToRow = 0
        self.ToCol = 0
        return
    def GetLength(self):
        return sizeof(tagMCActLianqiTileMove)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// AA 91 炼器活动玩家信息 //tagMCActLianqiPlayerInfo:
                                Row:%d,
                                Col:%d,
                                ToRow:%d,
                                ToCol:%d
                                '''\
                                %(
                                self.Row,
                                self.Col,
                                self.ToRow,
                                self.ToCol
                                )
        return DumpString
class  tagMCActLianqiPlayerInfo(Structure):
    Head = tagHead()
    Score = 0    #(DWORD Score)// 当前活动积分
    ScoreHighest = 0    #(DWORD ScoreHighest)// 当前活动最高积分,即上榜积分
    Energy = 0    #(WORD Energy)// 当前体力
    EnergyTime = 0    #(DWORD EnergyTime)// 上次恢复体力时间戳,为0时不用处理倒计时
    LVAwardMax = 0    #(DWORD LVAwardMax)// 已激活的最大合成奖励等级
    LVAwardState = 0    #(DWORD LVAwardState)// 最大合成等级奖励领取记录,按等级二进制位存储是否已领取
    UseItemLen = 0    #(BYTE UseItemLen)
    UseItemCntList = list()    #(vector<WORD> UseItemCntList)// 本局已使用辅助道具次数 [辅助道具1使用次数, ...]
    GridDataLen = 0    #(BYTE GridDataLen)// 格子数据长度
    GridData = ""    #(String GridData)// 格子二维行列数据,一定会同步,直接替换,行从上往下排 [[第1行格子1,格子2, ...], ...]
    OPType = 0    #(BYTE OPType)// 0-无(如初始化,GM等后端直接设置);1-移动;2-使用道具;3-重新开始;如果是因为操作引起的格子数据变化,则在相关操作表现完毕后再展示最新行列数据,否则直接变更
    MoveCount = 0    #(BYTE MoveCount)
    MoveList = list()    #(vector<tagMCActLianqiTileMove> MoveList)// 图块移动列表,可能没有数据,有的话先表现移动
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xAA
        self.Head.SubCmd = 0x91
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.Score,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.ScoreHighest,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.Energy,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.EnergyTime,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.LVAwardMax,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.LVAwardState,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.UseItemLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.UseItemLen):
            value,_pos=CommFunc.ReadWORD(_lpData,_pos)
            self.UseItemCntList.append(value)
        self.GridDataLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.GridData,_pos = CommFunc.ReadString(_lpData, _pos,self.GridDataLen)
        self.OPType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.MoveCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.MoveCount):
            temMoveList = tagMCActLianqiTileMove()
            _pos = temMoveList.ReadData(_lpData, _pos)
            self.MoveList.append(temMoveList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xAA
        self.Head.SubCmd = 0x91
        self.Score = 0
        self.ScoreHighest = 0
        self.Energy = 0
        self.EnergyTime = 0
        self.LVAwardMax = 0
        self.LVAwardState = 0
        self.UseItemLen = 0
        self.UseItemCntList = list()
        self.GridDataLen = 0
        self.GridData = ""
        self.OPType = 0
        self.MoveCount = 0
        self.MoveList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 4
        length += 4
        length += 2
        length += 4
        length += 4
        length += 4
        length += 1
        length += 2 * self.UseItemLen
        length += 1
        length += len(self.GridData)
        length += 1
        length += 1
        for i in range(self.MoveCount):
            length += self.MoveList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteDWORD(data, self.Score)
        data = CommFunc.WriteDWORD(data, self.ScoreHighest)
        data = CommFunc.WriteWORD(data, self.Energy)
        data = CommFunc.WriteDWORD(data, self.EnergyTime)
        data = CommFunc.WriteDWORD(data, self.LVAwardMax)
        data = CommFunc.WriteDWORD(data, self.LVAwardState)
        data = CommFunc.WriteBYTE(data, self.UseItemLen)
        for i in range(self.UseItemLen):
            data = CommFunc.WriteWORD(data, self.UseItemCntList[i])
        data = CommFunc.WriteBYTE(data, self.GridDataLen)
        data = CommFunc.WriteString(data, self.GridDataLen, self.GridData)
        data = CommFunc.WriteBYTE(data, self.OPType)
        data = CommFunc.WriteBYTE(data, self.MoveCount)
        for i in range(self.MoveCount):
            data = CommFunc.WriteString(data, self.MoveList[i].GetLength(), self.MoveList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                Score:%d,
                                ScoreHighest:%d,
                                Energy:%d,
                                EnergyTime:%d,
                                LVAwardMax:%d,
                                LVAwardState:%d,
                                UseItemLen:%d,
                                UseItemCntList:%s,
                                GridDataLen:%d,
                                GridData:%s,
                                OPType:%d,
                                MoveCount:%d,
                                MoveList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.Score,
                                self.ScoreHighest,
                                self.Energy,
                                self.EnergyTime,
                                self.LVAwardMax,
                                self.LVAwardState,
                                self.UseItemLen,
                                "...",
                                self.GridDataLen,
                                self.GridData,
                                self.OPType,
                                self.MoveCount,
                                "..."
                                )
        return DumpString
m_NAtagMCActLianqiPlayerInfo=tagMCActLianqiPlayerInfo()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActLianqiPlayerInfo.Head.Cmd,m_NAtagMCActLianqiPlayerInfo.Head.SubCmd))] = m_NAtagMCActLianqiPlayerInfo
#------------------------------------------------------
# AA 80 仙匣秘境跨服活动信息 #tagMCCrossActXianXiaMJInfo
class  tagMCCrossActXianXiaMJItem(Structure):
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py
@@ -26,6 +26,7 @@
import PlayerActXianXiaMJ
import PlayerActGubao
import PlayerActHorsePetTrain
import PlayerActLianqi
import CrossRealmMsg
import PyGameData
import PlayerFB
@@ -637,6 +638,9 @@
                elif actName == ShareDefine.CrossActName_HorsePetTrain:
                    PlayerActHorsePetTrain.OnCrossActIDChange(cfgID, zoneID, ipyData, state)
                    
                elif actName == ShareDefine.CrossActName_Lianqi:
                    PlayerActLianqi.OnCrossActIDChange(cfgID, zoneID, ipyData, state)
                else:
                    actChangeList.append([actName, ipyData, state, cfgID, groupName, zoneID, dbActID, actID, forceReset, dbTemplateID])
                    
@@ -660,6 +664,8 @@
                    PlayerActGubao.OnCrossActInStateRefresh(cfgID, zoneID, ipyData)
                elif actName == ShareDefine.CrossActName_HorsePetTrain:
                    PlayerActHorsePetTrain.OnCrossActInStateRefresh(cfgID, zoneID, ipyData)
                elif actName == ShareDefine.CrossActName_Lianqi:
                    PlayerActLianqi.OnCrossActInStateRefresh(cfgID, zoneID, ipyData)
                    
            # 仅活动有配置参与时间段的会触发
            if actID and dbActID == actID and dbStateJoin != stateJoin:
@@ -681,6 +687,9 @@
                    elif actName == ShareDefine.CrossActName_HorsePetTrain:
                        PlayerActHorsePetTrain.OnCrossActJoinEnd(cfgID, zoneID, ipyData)
                        
                    elif actName == ShareDefine.CrossActName_Lianqi:
                        PlayerActLianqi.OnCrossActJoinEnd(cfgID, zoneID, ipyData)
            GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_CrossActInfo % actName, crossActInfoDict[actName])
            # 非活动中的处理完关闭后,最后删除
            if not state and isEnd:
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
@@ -30,6 +30,7 @@
import PlayerActXianXiaMJ
import PlayerActGubao
import PlayerActHorsePetTrain
import PlayerActLianqi
import CrossActionControl
import CrossActAllRecharge
import CrossFamilyFlagwar
@@ -199,6 +200,9 @@
        elif msgType == ShareDefine.ClientServerMsg_HorsePetTrainScore:
            PlayerActHorsePetTrain.ClientServerMsg_HorsePetTrainScore(serverGroupID, msgData)
            
        elif msgType == ShareDefine.ClientServerMsg_LianqiScore:
            PlayerActLianqi.ClientServerMsg_LianqiScore(serverGroupID, msgData)
        elif msgType == ShareDefine.ClientServerMsg_CreateFuncTeam:
            PlayerFuncTeam.ClientServerMsg_CreateFuncTeam(serverGroupID, msgData)
            
ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
@@ -617,6 +617,26 @@
                        ("WORD", "XiangongID", 0),
                        ),
                "CrossActLianqi":(
                        ("DWORD", "CfgID", 1),
                        ("char", "ActGroupName", 0),
                        ("BYTE", "ZoneID", 0),
                        ("list", "ServerIDRangeList", 0),
                        ("char", "StartDate", 0),
                        ("char", "EndDate", 0),
                        ("char", "JoinStartTime", 0),
                        ("char", "JoinEndTime", 0),
                        ("WORD", "LVLimit", 0),
                        ("WORD", "PersonalTemplateID", 0),
                        ),
                "ActLianqiBillTemp":(
                        ("DWORD", "TemplateID", 1),
                        ("BYTE", "Rank", 0),
                        ("list", "AwardItemList", 0),
                        ("DWORD", "NeedScore", 0),
                        ),
                "ActXianXiaMJ":(
                        ("DWORD", "CfgID", 1),
                        ("list", "PlatformList", 0),
@@ -2075,6 +2095,36 @@
    def GetScoreAwardEx(self): return self.attrTuple[4] # 达标积分额外奖励 {积分:[[物品ID,个数,是否拍品], ...], ...} dict
    def GetXiangongID(self): return self.attrTuple[5] # 晋升仙宫ID WORD
# 炼器活动跨服表
class IPY_CrossActLianqi():
    def __init__(self):
        self.attrTuple = None
        return
    def GetCfgID(self): return self.attrTuple[0] # 配置ID DWORD
    def GetActGroupName(self): return self.attrTuple[1] # 活动组名(同组活动的名字需相同) char
    def GetZoneID(self): return self.attrTuple[2] # 组内分组编号 BYTE
    def GetServerIDRangeList(self): return self.attrTuple[3] # 活动的账号服务器ID范围列表 [[serverIDA, serverIDB], ...] list
    def GetStartDate(self): return self.attrTuple[4] # 开启日期 char
    def GetEndDate(self): return self.attrTuple[5] # 结束日期 char
    def GetJoinStartTime(self): return self.attrTuple[6] # 参与开始时间点 char
    def GetJoinEndTime(self): return self.attrTuple[7] # 参与结束时间点 char
    def GetLVLimit(self): return self.attrTuple[8] # 限制等级 WORD
    def GetPersonalTemplateID(self): return self.attrTuple[9] # 个人排行模板编号 WORD
# 炼器榜单模版表
class IPY_ActLianqiBillTemp():
    def __init__(self):
        self.attrTuple = None
        return
    def GetTemplateID(self): return self.attrTuple[0] # 模板编号 DWORD
    def GetRank(self): return self.attrTuple[1] # 名次 BYTE
    def GetAwardItemList(self): return self.attrTuple[2] # 奖励物品列表[[物品ID,个数,是否拍品], ...] list
    def GetNeedScore(self): return self.attrTuple[3] # 上榜所需积分 DWORD
# 仙匣秘境活动时间表
class IPY_ActXianXiaMJ():
    
@@ -3054,6 +3104,8 @@
        self.__LoadFileData("ActGubao", onlyCheck)
        self.__LoadFileData("CrossActGubao", onlyCheck)
        self.__LoadFileData("ActGubaoBillTemp", onlyCheck)
        self.__LoadFileData("CrossActLianqi", onlyCheck)
        self.__LoadFileData("ActLianqiBillTemp", onlyCheck)
        self.__LoadFileData("ActXianXiaMJ", onlyCheck)
        self.__LoadFileData("CrossActXianXiaMJ", onlyCheck)
        self.__LoadFileData("ActXianXiaMJBillTemp", onlyCheck)
@@ -3718,6 +3770,20 @@
        self.CheckLoadData("ActGubaoBillTemp")
        return self.ipyActGubaoBillTempCache[index]
    def GetCrossActLianqiCount(self):
        self.CheckLoadData("CrossActLianqi")
        return self.ipyCrossActLianqiLen
    def GetCrossActLianqiByIndex(self, index):
        self.CheckLoadData("CrossActLianqi")
        return self.ipyCrossActLianqiCache[index]
    def GetActLianqiBillTempCount(self):
        self.CheckLoadData("ActLianqiBillTemp")
        return self.ipyActLianqiBillTempLen
    def GetActLianqiBillTempByIndex(self, index):
        self.CheckLoadData("ActLianqiBillTemp")
        return self.ipyActLianqiBillTempCache[index]
    def GetActXianXiaMJCount(self):
        self.CheckLoadData("ActXianXiaMJ")
        return self.ipyActXianXiaMJLen
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerActLianqi.py
New file
@@ -0,0 +1,264 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package PlayerActLianqi
#
# @todo:炼器活动
# @author hxp
# @date 2025-01-09
# @version 1.0
#
# 详细描述: 炼器活动
#
#-------------------------------------------------------------------------------
#"""Version = 2025-01-09 17:30"""
#-------------------------------------------------------------------------------
import ShareDefine
import IpyGameDataPY
import PlayerDBGSEvent
import PlayerCompensation
import CrossActionControl
import CrossBillboard
import PyDataManager
import CrossRealmMsg
import GameWorld
def MapServer_Lianqi(curPlayer, msgList):
    mapID = curPlayer.GetRealMapID()
    playerID = curPlayer.GetPlayerID()
    GameWorld.DebugLog("MapServer_Lianqi mapID=%s,msgList=%s" % (mapID, msgList), playerID)
    if not msgList:
        return
    msgType, dataMsg = msgList
    ret = None
    if msgType == "ScoreHighest":
        ret = __OnLianqiScoreHighest(curPlayer, dataMsg)
    if ret == None:
        return
    return msgList + (ret if isinstance(ret, list) else [ret])
def __OnLianqiScoreHighest(curPlayer, dataMsg):
    ## 地图同步最高积分记录
    playerID = curPlayer.GetPlayerID()
    accID = curPlayer.GetAccID()
    playerName = curPlayer.GetName()
    job = curPlayer.GetJob()
    face = curPlayer.GetFace()
    facePic = curPlayer.GetFacePic()
    realmLV = curPlayer.GetOfficialRank()
    scoreHighest, lvHighest = dataMsg
    isRelationCrossAct = True
    if isRelationCrossAct:
        #同步跨服
        playerInfo = {"playerID":playerID, "playerName":playerName, "accID":accID, "job":job, "realmLV":realmLV,
                      "scoreHighest":scoreHighest, "lvHighest":lvHighest, "face":face, "facePic":facePic}
        SyncLianqiToCrossServer(curPlayer, playerInfo)
    return
def SyncLianqiToCrossServer(curPlayer, playerInfo):
    ## 同步到跨服服务器
    actInfo = CrossActionControl.GetPlayerCrossActInfo(curPlayer, ShareDefine.CrossActName_Lianqi)
    if not actInfo.get(ShareDefine.ActKey_State):
        return
    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
    ipyDataDict = actInfo.get(ShareDefine.ActKey_IpyDataInfo, {})
    if not ipyDataDict:
        return
    zoneID = ipyDataDict.get("ZoneID")
    if not cfgID or not zoneID:
        return
    dataMsg = {"cfgID":cfgID, "zoneID":zoneID, "playerInfo":playerInfo}
    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_LianqiScore, dataMsg)
    return
##------------------------------------------ 跨服炼器活动 ---------------------------------------
def ClientServerMsg_LianqiScore(serverGroupID, msgData):
    ## 收到子服 - 同步积分
    cfgID = msgData["cfgID"]
    zoneID = msgData["zoneID"]
    playerInfo = msgData["playerInfo"]
    actInfo = CrossActionControl.GetCrossActInfoByCfgID(ShareDefine.CrossActName_Lianqi, cfgID, zoneID)
    if not actInfo or not actInfo[ShareDefine.ActKey_State]:
        GameWorld.ErrLog("跨服炼器非活动中,无法更新! cfgID=%s, zoneID=%s" % (cfgID, zoneID))
        return
    if actInfo[ShareDefine.ActKey_StateJoin] != ShareDefine.ActStateJoin_Start:
        GameWorld.ErrLog("跨服炼器非可参与状态,无法更新! cfgID=%s, zoneID=%s" % (cfgID, zoneID))
        return
    ipyData = IpyGameDataPY.GetIpyGameData("CrossActLianqi", cfgID)
    if not ipyData:
        return
    PersonalTemplateID = ipyData.GetPersonalTemplateID()
    rankIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActLianqiBillTemp", PersonalTemplateID)
    if not rankIpyDataList:
        return
    lastRankIpyData = rankIpyDataList[-1] # 取最后一个为最低上榜积分限制
    personlLimit = lastRankIpyData.GetNeedScore()
    playerID = playerInfo["playerID"]
    playerName = playerInfo["playerName"]
    job = playerInfo["job"]
    accID = playerInfo["accID"]
    realmLV = playerInfo["realmLV"]
    face = playerInfo.get("face", 0)
    facePic = playerInfo.get("facePic", 0)
    scoreHighest = playerInfo["scoreHighest"]
    lvHighest = playerInfo["lvHighest"]
    groupValue1 = zoneID
    if scoreHighest >= personlLimit:
        name2, type2, value1, value2 = accID, job, realmLV, 0
        CrossBillboard.UpdCrossBillboard(ShareDefine.Def_CBT_LianqiScore, groupValue1, playerID, playerName,
                                         name2, type2, value1, value2, scoreHighest, cmpValue2=lvHighest, autoSort=False, value3=face, value4=facePic)
    return
def OnCrossActIDChange(cfgID, zoneID, ipyData, state):
    ## 跨服活动ID变更
    if state:
        OnCrossActStart(cfgID, zoneID, ipyData)
    else:
        OnCrossActEnd(cfgID, zoneID, ipyData)
    return
def OnCrossActStart(cfgID, zoneID, ipyData):
    ## 跨服活动开启
    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActLianqiAwardC % zoneID, 0)
    groupValue1 = zoneID
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    billboardObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_LianqiScore, groupValue1)
    billboardObj.ClearData() # 新活动重置榜单数据
    return
def OnCrossActEnd(cfgID, zoneID, ipyData):
    ## 跨服活动结束
    groupValue1 = zoneID
    GameWorld.Log("=== 跨服炼器活动结束! === cfgID=%s,zoneID=%s" % (cfgID, zoneID))
    __OnCrossEndAward(cfgID, zoneID, ipyData)
    # 备份、清除榜单数据
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    billboardObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_LianqiScore, groupValue1)
    billboardObj.ClearData()
    GameWorld.Log("=================================================================================")
    return
def OnCrossActInStateRefresh(cfgID, zoneID, ipyData):
    ## 活动中刷新,每次都需要刷新的逻辑,包含重读配置等
    if not ipyData:
        return
    PersonalTemplateID = ipyData.GetPersonalTemplateID()
    orderRuleList = GetOrderRuleList(PersonalTemplateID)
    groupValue1 = zoneID
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    billboardObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_LianqiScore, groupValue1)
    billboardObj.SetOrderRuleList(orderRuleList)
    return
def GetOrderRuleList(templateID):
    orderIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActLianqiBillTemp", templateID)
    if not orderIpyDataList:
        return
    orderRuleList = []
    for ipyData in orderIpyDataList:
        orderRuleList.append([ipyData.GetRank(), ipyData.GetNeedScore()])
    return orderRuleList
def OnCrossActJoinEnd(cfgID, zoneID, ipyData):
    ## 跨服活动参与结束
    __OnCrossEndAward(cfgID, zoneID, ipyData)
    return
def __OnCrossEndAward(cfgID, zoneID, ipyData):
    ## 结算跨服奖励
    awardState = PlayerDBGSEvent.GetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActLianqiAwardC % zoneID)
    if awardState:
        #已经结算过该活动
        GameWorld.Log("跨服炼器活动已经结算过奖励了! cfgID=%s,zoneID=%s" % (cfgID, zoneID))
        return
    PlayerDBGSEvent.SetDBGSTrig_ByKey(PlayerDBGSEvent.Def_ActLianqiAwardC % zoneID, 1)
    GameWorld.Log("=== 跨服炼器活动发放榜单奖励! === cfgID=%s,zoneID=%s" % (cfgID, zoneID))
    PersonalTemplateID = ipyData.GetPersonalTemplateID()
    serverIDRangeList = ipyData.GetServerIDRangeList()
    __GiveCrossOrderAwardPersonal(cfgID, zoneID, PersonalTemplateID, ShareDefine.Def_CBT_LianqiScore, serverIDRangeList)
    GameWorld.Log("=================================================================================")
    return
def __GiveCrossOrderAwardPersonal(cfgID, zoneID, templateID, billboardType, serverIDRangeList):
    groupValue1 = zoneID
    billboardMgr = PyDataManager.GetCrossBillboardManager()
    billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1)
    billboardDataCount = billboardObj.GetCount()
    if not billboardDataCount:
        GameWorld.Log("跨服炼器个人排行数据为空! billboardType=%s,zoneID=%s,cfgID=%s,templateID=%s" % (billboardType, zoneID, cfgID, templateID))
        return
    # 结算时排序并保存榜单数据流向
    billboardObj.SortData()
    billboardObj.SaveDRData("Award", {"cfgID":cfgID, "zoneID":zoneID})
    GameWorld.Log("结算跨服炼器个人排行奖励: billboardType=%s,zoneID=%s,cfgID=%s,templateID=%s,billboardDataCount=%s"
                  % (billboardType, zoneID, cfgID, templateID, billboardDataCount))
    orderIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActLianqiBillTemp", templateID)
    if not orderIpyDataList:
        return
    rankPre = 0
    billboardIndex = 0
    for ipyData in orderIpyDataList:
        rank = ipyData.GetRank()
        needScore = ipyData.GetNeedScore()
        scoreAwardEx = {} #ipyData.GetScoreAwardEx()
        scoreAwardExList = scoreAwardEx.keys()
        scoreAwardExList.sort()
        awardItemList = ipyData.GetAwardItemList()
        orderCountTotal = rank - rankPre # 奖励名次数量
        rankPre = rank
        for index in xrange(billboardIndex, billboardDataCount):
            if orderCountTotal <= 0:
                break
            billboardData = billboardObj.At(index)
            playerID = billboardData.ID
            name2 = billboardData.Name2
            cmpValue = billboardData.CmpValue
            if cmpValue < needScore:
                GameWorld.Log("    积分不足该榜单所需积分,跳过该名次: index=%s,rank=%s,playerID=%s,cmpValue=%s < %s" % (index, rank, playerID, cmpValue, needScore))
                break
            awardItemExList = []
            for scoreEx in scoreAwardExList:
                if cmpValue < scoreEx:
                    break
                awardItemExList = scoreAwardEx[scoreEx] # 取最大满足条件的一档
            finalAwardItemList = awardItemList + awardItemExList
            playerRank = rank - orderCountTotal + 1
            GameWorld.Log("    发放炼器个人榜单奖励: index=%s,rank=%s,playerRank=%s,playerID=%s,cmpValue=%s,awardItemList=%s,scoreAwardEx=%s,finalAwardItemList=%s, %s"
                          % (index, rank, playerRank, playerID, cmpValue, awardItemList, scoreAwardEx, finalAwardItemList, name2))
            PlayerCompensation.SendMailByKey("ActLianqiCrossPlayer", [playerID], finalAwardItemList, [playerRank], crossMail=True)
            orderCountTotal -= 1
            billboardIndex += 1
    return
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerDBGSEvent.py
@@ -190,6 +190,8 @@
Def_ActHorsePetTrainAward = "ActHorsePetTrainAward_%s"
#跨服骑宠养成结算状态,参数(zoneID)
Def_ActHorsePetTrainAwardC = "ActHorsePetTrainAwardC_%s"
#跨服炼器结算状态,参数(zoneID)
Def_ActLianqiAwardC = "ActLianqiAwardC_%s"
def SetInitOpenServerTime(initTime):
    openDatetime = GameWorld.ChangeTimeNumToDatetime(initTime)
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
@@ -80,6 +80,7 @@
import CrossActAllRecharge
import PlayerActGubao
import PlayerActHorsePetTrain
import PlayerActLianqi
import PlayerActXianXiaMJ
import PlayerActBossTrial
import PlayerActFamilyCTGAssist
@@ -714,6 +715,14 @@
        PlayerActHorsePetTrain.MapServer_HorsePetTrain(curPlayer, eval(resultName))
        return
    
    # 炼器
    if callName == "ActLianqi":
        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID)
        if not curPlayer:
            return
        PlayerActLianqi.MapServer_Lianqi(curPlayer, eval(resultName))
        return
    #py喇叭聊天
    if callName == 'PYSpeaker':
        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID)
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -363,10 +363,11 @@
CrossActName_XianXiaMJ = "CrossActXianXiaMJ" # 仙匣秘境 - 跨服
CrossActName_Gubao = "CrossActGubao" # 古宝养成 - 跨服
CrossActName_HorsePetTrain = "CrossActHorsePetTrain" # 骑宠养成 - 跨服
CrossActName_Lianqi = "CrossActLianqi" # 炼器 - 跨服
#跨服运营活动列表
CrossActNameList = [CrossActName_CTGBillboard, CrossActName_AllRecharge, CrossActName_LuckyCloudBuy, CrossActName_BossTrial, 
                    CrossActName_XianXiaMJ, CrossActName_Gubao, CrossActName_HorsePetTrain]
                    CrossActName_XianXiaMJ, CrossActName_Gubao, CrossActName_HorsePetTrain, CrossActName_Lianqi]
#需要锁定活动分区分配直到活动结束的跨服运营活动,即使热更分区配置,也不会改变正在活动中的分区设定,直到活动结束
CrossActLockServerGroupIDList = [CrossActName_CTGBillboard, CrossActName_AllRecharge]
@@ -902,7 +903,8 @@
Def_CBT_GubaoScore, # 古宝养成积分 - 个人榜  163
Def_CBT_HorsePetTrainScore, # 骑宠养成积分 - 个人榜  164
Def_CBT_CrossRealmPK, # 跨服PK竞技场  165
) = range(150, 165 + 1)
Def_CBT_LianqiScore, # 炼器积分 - 个人榜  166
) = range(150, 166 + 1)
#职业对应战力排行榜类型
JobFightPowerBillboardDict = {
@@ -1725,6 +1727,7 @@
ClientServerMsg_GubaoScore = "GubaoScore" # 古宝养成积分
ClientServerMsg_HorsePetTrainScore = "HorsePetTrainScore" # 骑宠养成积分
ClientServerMsg_QueryXiangong = "QueryXiangong" # 查看仙宫仙名录
ClientServerMsg_LianqiScore = "LianqiScore" # 炼器积分
#跨服广播类型定义
CrossNotify_CrossAct = "CrossAct"
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1677,6 +1677,18 @@
PacketSubCMD_3=0x22
PacketCallFunc_3=OnActGodGiftReset
;炼器活动
[PlayerActLianqi]
ScriptName = Player\PlayerActLianqi.py
Writer = hxp
Releaser = hxp
RegType = 0
RegisterPackCount = 1
PacketCMD_1=0xAA
PacketSubCMD_1=0x25
PacketCallFunc_1=OnActLianqiOP
;集字活动
[PlayerActCollectWords]
ScriptName = Player\PlayerActCollectWords.py
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -4156,6 +4156,17 @@
Def_PDict_ActHorsePetTrainID = "ActHorsePetTrainID_%s"  # 玩家身上的活动ID,唯一标识,取活动开始日期time值,参数:(活动编号)
Def_PDict_ActHorsePetTrainScore = "ActHorsePetTrainScore_%s"  # 累计获得活动养成积分,参数:(活动编号)
#炼器活动
Def_PDict_CA_LianqiID = "CA_LianqiID"  # 玩家身上的活动ID,唯一标识,取活动开始日期time值
Def_PDict_LianqiScore = "LianqiScore"  # 当前积分
Def_PDict_LianqiScoreHighest = "LianqiScoreHighest"  # 本次最高分(上榜分取该分)
Def_PDict_LianqiEnergy = "LianqiEnergy"  # 当前体力
Def_PDict_LianqiEnergyTime = "LianqiEnergyTime"  # 上次恢复体力时间戳
Def_PDict_LianqiRowData = "LianqiRowData_%s"  # 行数据,最大支持每行4格,每格存两位,参数:(key编号)
Def_PDict_LianqiItemUse = "LianqiItemUse_%s"  # 辅助道具单局已使用次数,参数:(物品ID)
Def_PDict_LianqiLVAwardMax = "LianqiLVAwardMax"  # 激活的最大合成奖励等级
Def_PDict_LianqiLVAwardState = "LianqiLVAwardState"  # 最大合成等级奖励领取记录,按二进制位存储是否已领取
#天帝礼包活动
Def_PDict_GodGiftID = "ActGodGiftID_%s"  # 玩家身上的活动ID,唯一标识,取活动开始日期time值,参数:(活动编号)
Def_PDict_GodGiftWorldLV = "ActGodGiftWorldLV_%s" #玩家身上的活动世界等级,参数:(活动编号)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -16711,6 +16711,70 @@
#------------------------------------------------------
# AA 25 炼器操作 #tagCMActLianqiOP
class  tagCMActLianqiOP(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("OPType", c_ubyte),    # 1-移动;2-使用道具;3-重新开始;4-领取等级奖励
                  ("OPValue", c_int),    # 移动时-发1上2下3左4右;使用道具时-发使用个数*10+道具ID所在配置索引;等级奖励时-发领取的奖励等级
                  ("OPValue2", c_int),    # 使用道具时-发选中格子A的行列值 行*10+列
                  ("OPValue3", c_int),    # 使用道具时-发选中格子B的行列值 行*10+列
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xAA
        self.SubCmd = 0x25
        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 = 0xAA
        self.SubCmd = 0x25
        self.OPType = 0
        self.OPValue = 0
        self.OPValue2 = 0
        self.OPValue3 = 0
        return
    def GetLength(self):
        return sizeof(tagCMActLianqiOP)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// AA 25 炼器操作 //tagCMActLianqiOP:
                                Cmd:%s,
                                SubCmd:%s,
                                OPType:%d,
                                OPValue:%d,
                                OPValue2:%d,
                                OPValue3:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.OPType,
                                self.OPValue,
                                self.OPValue2,
                                self.OPValue3
                                )
        return DumpString
m_NAtagCMActLianqiOP=tagCMActLianqiOP()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMActLianqiOP.Cmd,m_NAtagCMActLianqiOP.SubCmd))] = m_NAtagCMActLianqiOP
#------------------------------------------------------
# AA 12 选择转盘活动物品 #tagCMActTurntableChooseItem
class  tagCMActTurntableChooseItem(Structure):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -44354,6 +44354,434 @@
#------------------------------------------------------
# AA 90 炼器跨服活动信息 #tagMCCrossActLianqiInfo
class  tagMCCrossActLianqiItem(Structure):
    _pack_ = 1
    _fields_ = [
                  ("ItemID", c_int),
                  ("ItemCount", c_ushort),
                  ("IsBind", 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.ItemID = 0
        self.ItemCount = 0
        self.IsBind = 0
        return
    def GetLength(self):
        return sizeof(tagMCCrossActLianqiItem)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// AA 90 炼器跨服活动信息 //tagMCCrossActLianqiInfo:
                                ItemID:%d,
                                ItemCount:%d,
                                IsBind:%d
                                '''\
                                %(
                                self.ItemID,
                                self.ItemCount,
                                self.IsBind
                                )
        return DumpString
class  tagMCCrossActLianqiBillard(Structure):
    Rank = 0    #(DWORD Rank)// 名次,1-代表第一名;支持夸段,如1,3 代表第1名,第2~3名
    Count = 0    #(BYTE Count)// 奖励物品数
    AwardItemList = list()    #(vector<tagMCCrossActLianqiItem> AwardItemList)// 奖励物品列表
    NeedScore = 0    #(DWORD NeedScore)// 上榜所需积分
    data = None
    def __init__(self):
        self.Clear()
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        self.Rank,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.Count):
            temAwardItemList = tagMCCrossActLianqiItem()
            _pos = temAwardItemList.ReadData(_lpData, _pos)
            self.AwardItemList.append(temAwardItemList)
        self.NeedScore,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        return _pos
    def Clear(self):
        self.Rank = 0
        self.Count = 0
        self.AwardItemList = list()
        self.NeedScore = 0
        return
    def GetLength(self):
        length = 0
        length += 4
        length += 1
        for i in range(self.Count):
            length += self.AwardItemList[i].GetLength()
        length += 4
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteDWORD(data, self.Rank)
        data = CommFunc.WriteBYTE(data, self.Count)
        for i in range(self.Count):
            data = CommFunc.WriteString(data, self.AwardItemList[i].GetLength(), self.AwardItemList[i].GetBuffer())
        data = CommFunc.WriteDWORD(data, self.NeedScore)
        return data
    def OutputString(self):
        DumpString = '''
                                Rank:%d,
                                Count:%d,
                                AwardItemList:%s,
                                NeedScore:%d
                                '''\
                                %(
                                self.Rank,
                                self.Count,
                                "...",
                                self.NeedScore
                                )
        return DumpString
class  tagMCCrossActLianqiInfo(Structure):
    Head = tagHead()
    ServerInfoLen = 0    #(BYTE ServerInfoLen)
    ServerIDRangeInfo = ""    #(String ServerIDRangeInfo)//开放该活动的服务器ID范围列表,json格式 [[IDA, IDB], ...], [] 为全服
    GroupValue1 = 0    #(BYTE GroupValue1)// 活动榜单分组值1,用于查询对应榜单
    StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
    EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
    JoinStartTime = ""    #(char JoinStartTime[5])// 参与开始时间点 mm:ss
    JoinEndTime = ""    #(char JoinEndTime[5])// 参与结束时间点 mm:ss
    LimitLV = 0    #(WORD LimitLV)// 限制等级
    PersonalBillCount = 0    #(BYTE PersonalBillCount)
    PersonalBillboardInfoList = list()    #(vector<tagMCCrossActLianqiBillard> PersonalBillboardInfoList)// 个人榜单奖励信息列表,如果没有代表本次活动没有该榜奖励
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xAA
        self.Head.SubCmd = 0x90
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.ServerInfoLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.ServerIDRangeInfo,_pos = CommFunc.ReadString(_lpData, _pos,self.ServerInfoLen)
        self.GroupValue1,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
        self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
        self.JoinStartTime,_pos = CommFunc.ReadString(_lpData, _pos,5)
        self.JoinEndTime,_pos = CommFunc.ReadString(_lpData, _pos,5)
        self.LimitLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.PersonalBillCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.PersonalBillCount):
            temPersonalBillboardInfoList = tagMCCrossActLianqiBillard()
            _pos = temPersonalBillboardInfoList.ReadData(_lpData, _pos)
            self.PersonalBillboardInfoList.append(temPersonalBillboardInfoList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xAA
        self.Head.SubCmd = 0x90
        self.ServerInfoLen = 0
        self.ServerIDRangeInfo = ""
        self.GroupValue1 = 0
        self.StartDate = ""
        self.EndtDate = ""
        self.JoinStartTime = ""
        self.JoinEndTime = ""
        self.LimitLV = 0
        self.PersonalBillCount = 0
        self.PersonalBillboardInfoList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += len(self.ServerIDRangeInfo)
        length += 1
        length += 10
        length += 10
        length += 5
        length += 5
        length += 2
        length += 1
        for i in range(self.PersonalBillCount):
            length += self.PersonalBillboardInfoList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.ServerInfoLen)
        data = CommFunc.WriteString(data, self.ServerInfoLen, self.ServerIDRangeInfo)
        data = CommFunc.WriteBYTE(data, self.GroupValue1)
        data = CommFunc.WriteString(data, 10, self.StartDate)
        data = CommFunc.WriteString(data, 10, self.EndtDate)
        data = CommFunc.WriteString(data, 5, self.JoinStartTime)
        data = CommFunc.WriteString(data, 5, self.JoinEndTime)
        data = CommFunc.WriteWORD(data, self.LimitLV)
        data = CommFunc.WriteBYTE(data, self.PersonalBillCount)
        for i in range(self.PersonalBillCount):
            data = CommFunc.WriteString(data, self.PersonalBillboardInfoList[i].GetLength(), self.PersonalBillboardInfoList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                ServerInfoLen:%d,
                                ServerIDRangeInfo:%s,
                                GroupValue1:%d,
                                StartDate:%s,
                                EndtDate:%s,
                                JoinStartTime:%s,
                                JoinEndTime:%s,
                                LimitLV:%d,
                                PersonalBillCount:%d,
                                PersonalBillboardInfoList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.ServerInfoLen,
                                self.ServerIDRangeInfo,
                                self.GroupValue1,
                                self.StartDate,
                                self.EndtDate,
                                self.JoinStartTime,
                                self.JoinEndTime,
                                self.LimitLV,
                                self.PersonalBillCount,
                                "..."
                                )
        return DumpString
m_NAtagMCCrossActLianqiInfo=tagMCCrossActLianqiInfo()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCCrossActLianqiInfo.Head.Cmd,m_NAtagMCCrossActLianqiInfo.Head.SubCmd))] = m_NAtagMCCrossActLianqiInfo
#------------------------------------------------------
# AA 91 炼器活动玩家信息 #tagMCActLianqiPlayerInfo
class  tagMCActLianqiTileMove(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Row", c_ubyte),    # 行,0为第1行
                  ("Col", c_ubyte),    # 列,0为第1列
                  ("ToRow", c_ubyte),    # 移动到目标行
                  ("ToCol", 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.Row = 0
        self.Col = 0
        self.ToRow = 0
        self.ToCol = 0
        return
    def GetLength(self):
        return sizeof(tagMCActLianqiTileMove)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// AA 91 炼器活动玩家信息 //tagMCActLianqiPlayerInfo:
                                Row:%d,
                                Col:%d,
                                ToRow:%d,
                                ToCol:%d
                                '''\
                                %(
                                self.Row,
                                self.Col,
                                self.ToRow,
                                self.ToCol
                                )
        return DumpString
class  tagMCActLianqiPlayerInfo(Structure):
    Head = tagHead()
    Score = 0    #(DWORD Score)// 当前活动积分
    ScoreHighest = 0    #(DWORD ScoreHighest)// 当前活动最高积分,即上榜积分
    Energy = 0    #(WORD Energy)// 当前体力
    EnergyTime = 0    #(DWORD EnergyTime)// 上次恢复体力时间戳,为0时不用处理倒计时
    LVAwardMax = 0    #(DWORD LVAwardMax)// 已激活的最大合成奖励等级
    LVAwardState = 0    #(DWORD LVAwardState)// 最大合成等级奖励领取记录,按等级二进制位存储是否已领取
    UseItemLen = 0    #(BYTE UseItemLen)
    UseItemCntList = list()    #(vector<WORD> UseItemCntList)// 本局已使用辅助道具次数 [辅助道具1使用次数, ...]
    GridDataLen = 0    #(BYTE GridDataLen)// 格子数据长度
    GridData = ""    #(String GridData)// 格子二维行列数据,一定会同步,直接替换,行从上往下排 [[第1行格子1,格子2, ...], ...]
    OPType = 0    #(BYTE OPType)// 0-无(如初始化,GM等后端直接设置);1-移动;2-使用道具;3-重新开始;如果是因为操作引起的格子数据变化,则在相关操作表现完毕后再展示最新行列数据,否则直接变更
    MoveCount = 0    #(BYTE MoveCount)
    MoveList = list()    #(vector<tagMCActLianqiTileMove> MoveList)// 图块移动列表,可能没有数据,有的话先表现移动
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xAA
        self.Head.SubCmd = 0x91
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.Score,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.ScoreHighest,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.Energy,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.EnergyTime,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.LVAwardMax,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.LVAwardState,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.UseItemLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.UseItemLen):
            value,_pos=CommFunc.ReadWORD(_lpData,_pos)
            self.UseItemCntList.append(value)
        self.GridDataLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.GridData,_pos = CommFunc.ReadString(_lpData, _pos,self.GridDataLen)
        self.OPType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.MoveCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.MoveCount):
            temMoveList = tagMCActLianqiTileMove()
            _pos = temMoveList.ReadData(_lpData, _pos)
            self.MoveList.append(temMoveList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xAA
        self.Head.SubCmd = 0x91
        self.Score = 0
        self.ScoreHighest = 0
        self.Energy = 0
        self.EnergyTime = 0
        self.LVAwardMax = 0
        self.LVAwardState = 0
        self.UseItemLen = 0
        self.UseItemCntList = list()
        self.GridDataLen = 0
        self.GridData = ""
        self.OPType = 0
        self.MoveCount = 0
        self.MoveList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 4
        length += 4
        length += 2
        length += 4
        length += 4
        length += 4
        length += 1
        length += 2 * self.UseItemLen
        length += 1
        length += len(self.GridData)
        length += 1
        length += 1
        for i in range(self.MoveCount):
            length += self.MoveList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteDWORD(data, self.Score)
        data = CommFunc.WriteDWORD(data, self.ScoreHighest)
        data = CommFunc.WriteWORD(data, self.Energy)
        data = CommFunc.WriteDWORD(data, self.EnergyTime)
        data = CommFunc.WriteDWORD(data, self.LVAwardMax)
        data = CommFunc.WriteDWORD(data, self.LVAwardState)
        data = CommFunc.WriteBYTE(data, self.UseItemLen)
        for i in range(self.UseItemLen):
            data = CommFunc.WriteWORD(data, self.UseItemCntList[i])
        data = CommFunc.WriteBYTE(data, self.GridDataLen)
        data = CommFunc.WriteString(data, self.GridDataLen, self.GridData)
        data = CommFunc.WriteBYTE(data, self.OPType)
        data = CommFunc.WriteBYTE(data, self.MoveCount)
        for i in range(self.MoveCount):
            data = CommFunc.WriteString(data, self.MoveList[i].GetLength(), self.MoveList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                Score:%d,
                                ScoreHighest:%d,
                                Energy:%d,
                                EnergyTime:%d,
                                LVAwardMax:%d,
                                LVAwardState:%d,
                                UseItemLen:%d,
                                UseItemCntList:%s,
                                GridDataLen:%d,
                                GridData:%s,
                                OPType:%d,
                                MoveCount:%d,
                                MoveList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.Score,
                                self.ScoreHighest,
                                self.Energy,
                                self.EnergyTime,
                                self.LVAwardMax,
                                self.LVAwardState,
                                self.UseItemLen,
                                "...",
                                self.GridDataLen,
                                self.GridData,
                                self.OPType,
                                self.MoveCount,
                                "..."
                                )
        return DumpString
m_NAtagMCActLianqiPlayerInfo=tagMCActLianqiPlayerInfo()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActLianqiPlayerInfo.Head.Cmd,m_NAtagMCActLianqiPlayerInfo.Head.SubCmd))] = m_NAtagMCActLianqiPlayerInfo
#------------------------------------------------------
# AA 80 仙匣秘境跨服活动信息 #tagMCCrossActXianXiaMJInfo
class  tagMCCrossActXianXiaMJItem(Structure):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Lianqi.py
New file
@@ -0,0 +1,134 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.Lianqi
#
# @todo:炼器活动
# @author hxp
# @date 2025-01-09
# @version 1.0
#
# 详细描述: 炼器活动
#
#-------------------------------------------------------------------------------
#"""Version = 2025-01-09 17:30"""
#-------------------------------------------------------------------------------
import GameWorld
import PlayerControl
import PlayerZhanling
import PlayerActLianqi
import IpyGameDataPY
import ChConfig
#---------------------------------------------------------------------
#逻辑实现
## GM命令执行入口
#  @param curPlayer 当前玩家
#  @param msgList 参数列表
#  @return None
#  @remarks 函数详细说明.
def OnExec(curPlayer, msgList):
    if not msgList:
        GameWorld.DebugAnswer(curPlayer, "重置炼器数据: Lianqi 0")
        GameWorld.DebugAnswer(curPlayer, "重新开始游戏: Lianqi 1")
        GameWorld.DebugAnswer(curPlayer, "设置辅助道具: Lianqi w ID索引 已用次数")
        GameWorld.DebugAnswer(curPlayer, "设置当前体力: Lianqi e 体力值")
        GameWorld.DebugAnswer(curPlayer, "设置当前积分: Lianqi s 积分")
        GameWorld.DebugAnswer(curPlayer, "设置网格等级: Lianqi g 行 列 等级")
        GameWorld.DebugAnswer(curPlayer, "输出棋盘数据: Lianqi p")
        GameWorld.DebugAnswer(curPlayer, "设置棋盘数据: Lianqi c 行列等级1 ...")
        GameWorld.DebugAnswer(curPlayer, "棋盘行列从行0~3列0~3开始总16格,不足的值默认0")
        return
    if not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_LianqiID):
        GameWorld.DebugAnswer(curPlayer, "炼器非活动中")
        return
    value1 = msgList[0]
    if value1 == 0:
        PlayerZhanling.ResetZhanling(curPlayer, PlayerZhanling.ZhanlingType_Lianqi)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiScore, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiScoreHighest, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiLVAwardMax, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiLVAwardState, 0)
        PlayerActLianqi.SetLianqiEnergy(curPlayer, IpyGameDataPY.GetFuncCfg("LianqiSet", 1))
        PlayerActLianqi.ReStartGame(curPlayer, isNotify=False)
        GameWorld.DebugAnswer(curPlayer, "重置炼器OK!")
    elif value1 == 1:
        PlayerActLianqi.ReStartGame(curPlayer, isNotify=False)
        GameWorld.DebugAnswer(curPlayer, "重新开始炼器OK!")
    elif value1 == "e":
        energy = msgList[1] if len(msgList) > 1 else 0
        updEnergy = PlayerActLianqi.SetLianqiEnergy(curPlayer, energy)
        GameWorld.DebugAnswer(curPlayer, "设置体力: %s" % updEnergy)
    elif value1 == "s":
        score = msgList[1] if len(msgList) > 1 else 0
        updScore = PlayerActLianqi.SetLianqiScore(curPlayer, score)
        GameWorld.DebugAnswer(curPlayer, "设置积分: %s" % updScore)
    elif value1 == "g":
        r = msgList[1] if len(msgList) > 1 else 0
        c = msgList[2] if len(msgList) > 2 else 0
        lv = msgList[3] if len(msgList) > 3 else 0
        gridDataList = PlayerActLianqi.GetGridDataList(curPlayer)
        rcLV = PlayerActLianqi.GetGridLV(r, c, gridDataList)
        if rcLV == None:
            GameWorld.DebugAnswer(curPlayer, "该行列不存在!行:%s,列:%s" % (r, c))
            return
        lv = min(lv, PlayerActLianqi.Def_MaxLV)
        gridDataList[r][c] = lv
        PlayerActLianqi.SaveGridData(curPlayer, gridDataList)
        GameWorld.DebugAnswer(curPlayer, "设置行:%s,列:%s,等级:%s" % (r, c, lv))
        __PrintGrid(curPlayer)
    elif value1 == "p":
        __PrintGrid(curPlayer)
    elif value1 == "c":
        rcvList = msgList[1:]
        gridMax = PlayerActLianqi.Def_Size *PlayerActLianqi.Def_Size
        if len(rcvList) < gridMax:
            rcvList += [0] * (gridMax - len(rcvList))
        gridDataList = PlayerActLianqi.GetGridDataList(curPlayer)
        for r in range(PlayerActLianqi.Def_Size):
            for c in range(PlayerActLianqi.Def_Size):
                lv = rcvList.pop(0)
                gridDataList[r][c] = min(lv, PlayerActLianqi.Def_MaxLV)
        PlayerActLianqi.SaveGridData(curPlayer, gridDataList)
        GameWorld.DebugAnswer(curPlayer, "设置棋盘OK!")
        __PrintGrid(curPlayer)
    elif value1 == "w":
        idIndex = msgList[1] if len(msgList) > 1 else 0
        usedCnt = msgList[2] if len(msgList) > 2 else 0
        itemIDList = IpyGameDataPY.GetFuncEvalCfg("LianqiUseItem", 1)
        if idIndex < 0 or idIndex >= len(itemIDList):
            GameWorld.DebugAnswer(curPlayer, "非辅助道具ID索引:%s,%s" % (idIndex, range(len(itemIDList))))
            return
        itemID = itemIDList[idIndex]
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiItemUse % itemID, usedCnt)
        GameWorld.DebugAnswer(curPlayer, "设置物品ID:%s,使用次数:%s" % (itemID, usedCnt))
    PlayerActLianqi.Sync_LianqiPlayerInfo(curPlayer)
    return
def __PrintGrid(curPlayer):
    gridDataList = PlayerActLianqi.GetGridDataList(curPlayer)
    for rowData in gridDataList:
        rowStr = ""
        for lv in rowData:
            if rowStr:
                rowStr += ", "
            if lv < 10:
                rowStr += "  "
            rowStr += str(lv)
        GameWorld.DebugAnswer(curPlayer, "[%s]" % rowStr)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1606,6 +1606,13 @@
                        ("dict", "ScoreAwardEx", 0),
                        ),
                "ActLianqiBillTemp":(
                        ("DWORD", "TemplateID", 1),
                        ("BYTE", "Rank", 0),
                        ("list", "AwardItemList", 0),
                        ("DWORD", "NeedScore", 0),
                        ),
                "ActXianXiaMJ":(
                        ("DWORD", "CfgID", 1),
                        ("char", "StartDate", 0),
@@ -4888,6 +4895,18 @@
    def GetNeedScore(self): return self.attrTuple[3] # 上榜所需积分 DWORD
    def GetScoreAwardEx(self): return self.attrTuple[4] # 达标积分额外奖励 {积分:[[物品ID,个数,是否拍品], ...], ...} dict
# 炼器榜单模版表
class IPY_ActLianqiBillTemp():
    def __init__(self):
        self.attrTuple = None
        return
    def GetTemplateID(self): return self.attrTuple[0] # 模板编号 DWORD
    def GetRank(self): return self.attrTuple[1] # 名次 BYTE
    def GetAwardItemList(self): return self.attrTuple[2] # 奖励物品列表[[物品ID,个数,是否拍品], ...] list
    def GetNeedScore(self): return self.attrTuple[3] # 上榜所需积分 DWORD
# 仙匣秘境活动时间表
class IPY_ActXianXiaMJ():
    
@@ -6610,6 +6629,7 @@
        self.__LoadFileData("ActHorsePetTrainBillTemp", onlyCheck)
        self.__LoadFileData("ActGubao", onlyCheck)
        self.__LoadFileData("ActGubaoBillTemp", onlyCheck)
        self.__LoadFileData("ActLianqiBillTemp", onlyCheck)
        self.__LoadFileData("ActXianXiaMJ", onlyCheck)
        self.__LoadFileData("ActXianXiaMJBillTemp", onlyCheck)
        self.__LoadFileData("ActXianXiaMJAward", onlyCheck)
@@ -7981,6 +8001,13 @@
        self.CheckLoadData("ActGubaoBillTemp")
        return self.ipyActGubaoBillTempCache[index]
    def GetActLianqiBillTempCount(self):
        self.CheckLoadData("ActLianqiBillTemp")
        return self.ipyActLianqiBillTempLen
    def GetActLianqiBillTempByIndex(self, index):
        self.CheckLoadData("ActLianqiBillTemp")
        return self.ipyActLianqiBillTempCache[index]
    def GetActXianXiaMJCount(self):
        self.CheckLoadData("ActXianXiaMJ")
        return self.ipyActXianXiaMJLen
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -115,6 +115,7 @@
import PlayerActXianXiaMJ
import PlayerActGubao
import PlayerActHorsePetTrain
import PlayerActLianqi
import PlayerActGodGift
import PlayerActFamilyCTGAssist
import PlayerActRechargeRebateGold
@@ -908,6 +909,8 @@
    PlayerActGubao.OnPlayerLogin(curPlayer)
    # 骑宠养成活动
    PlayerActHorsePetTrain.OnPlayerLogin(curPlayer)
    # 炼器活动
    PlayerActLianqi.OnPlayerLogin(curPlayer)
    # 天帝礼包活动
    PlayerActGodGift.OnPlayerLogin(curPlayer)
    # 多日连充活动
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActLianqi.py
New file
@@ -0,0 +1,635 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Player.PlayerActLianqi
#
# @todo:炼器活动
# @author hxp
# @date 2025-01-09
# @version 1.0
#
# 详细描述: 炼器活动
#
#-------------------------------------------------------------------------------
#"""Version = 2025-01-09 17:30"""
#-------------------------------------------------------------------------------
import ShareDefine
import PlayerControl
import IpyGameDataPY
import NetPackCommon
import ChPyNetSendPack
import CrossRealmPlayer
import PlayerZhanling
import ItemControler
import ItemCommon
import GameWorld
import ChConfig
import random
import time
Def_Size = 4 # 行列数
Def_MaxLV = 11 # 最大等级,2048
def OnPlayerLogin(curPlayer):
    if not __CheckPlayerCrossActLianqi(curPlayer):
        Sync_CrossActLianqiActionInfo(curPlayer)
        Sync_LianqiPlayerInfo(curPlayer)
    return
def RefreshCrossActLianqiInfo():
    ## 收到GameServer同步的活动信息,刷新活动信息
    playerManager = GameWorld.GetPlayerManager()
    for index in xrange(playerManager.GetPlayerCount()):
        curPlayer = playerManager.GetPlayerByIndex(index)
        if not GameWorld.IsNormalPlayer(curPlayer):
            continue
        __CheckPlayerCrossActLianqi(curPlayer)
    return
def __CheckPlayerCrossActLianqi(curPlayer):
    playerID = curPlayer.GetPlayerID()
    actInfo = CrossRealmPlayer.GetPlayerCrossActInfo(curPlayer, ShareDefine.CrossActName_Lianqi)
    cfgID = actInfo.get(ShareDefine.ActKey_CfgID, 0)
    actID = actInfo.get(ShareDefine.ActKey_ID, 0)
    state = actInfo.get(ShareDefine.ActKey_State, 0)
    playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_LianqiID) # 玩家身上的活动ID
    # 活动ID 相同的话不处理
    if actID == playerActID:
        GameWorld.DebugLog("跨服炼器活动ID不变,不处理!cfgID=%s,actID=%s" % (cfgID, actID), playerID)
        return
    GameWorld.DebugLog("跨服炼器活动重置! cfgID=%s,actID=%s,playerActID=%s,state=%s" % (cfgID, actID, playerActID, state), playerID)
    PlayerZhanling.ResetZhanling(curPlayer, PlayerZhanling.ZhanlingType_Lianqi)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CA_LianqiID, actID)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiScore, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiScoreHighest, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiEnergy, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiEnergyTime, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiLVAwardMax, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiLVAwardState, 0)
    for row in range(Def_Size):
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiRowData % row, 0)
    for itemID in IpyGameDataPY.GetFuncEvalCfg("LianqiUseItem", 1):
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiItemUse % itemID, 0)
    # 回收道具
    for itemID in IpyGameDataPY.GetFuncEvalCfg("LianqiUseItem", 5):
        ItemControler.RecycleItem(curPlayer, itemID, "ActLianqiRecycleItem")
    if state:
        SetLianqiEnergy(curPlayer, IpyGameDataPY.GetFuncCfg("LianqiSet", 1))
        ReStartGame(curPlayer, isNotify=False)
        Sync_CrossActLianqiActionInfo(curPlayer)
        Sync_LianqiPlayerInfo(curPlayer)
    else:
        CrossRealmPlayer.NotifyCrossActEnd(curPlayer, ShareDefine.CrossActName_Lianqi)
    return True
def ReStartGame(curPlayer, opType=0, isNotify=True):
    ## 重新开始游戏
    # 重置积分
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiScore, 0)
    # 重置单局使用道具次数
    for itemID in IpyGameDataPY.GetFuncEvalCfg("LianqiUseItem", 1):
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiItemUse % itemID, 0)
    # 初始化棋盘
    initRandCount = IpyGameDataPY.GetFuncCfg("LianqiRand", 1)
    randList = range(Def_Size * Def_Size)
    random.shuffle(randList)
    randList = randList[:initRandCount]
    gridDataList = []
    for row in range(Def_Size):
        rowDataList = []
        for col in range(Def_Size):
            lv = 1 if (row * Def_Size + col) in randList else 0
            rowDataList.append(lv)
        gridDataList.append(rowDataList)
    PrintGridData(curPlayer, gridDataList, "重新开始炼器: %s" % randList)
    SaveGridData(curPlayer, gridDataList)
    if isNotify:
        Sync_LianqiPlayerInfo(curPlayer, opType)
    return
def GetGridDataList(curPlayer):
    ## 获取行列数据列表
    gridDataList = []
    for row in range(Def_Size):
        rowDataValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiRowData % row)
        rowDataList = []
        for _ in range(Def_Size):
            colValue = rowDataValue % 100
            rowDataValue = rowDataValue / 100
            rowDataList.insert(0, colValue)
        gridDataList.append(rowDataList)
    return gridDataList
def PrintGridData(curPlayer, gridDataList, printTitle):
    GameWorld.DebugLog("%s" % printTitle, curPlayer.GetPlayerID())
    for rowData in gridDataList:
        rowStr = ""
        for lv in rowData:
            if rowStr:
                rowStr += ", "
            if lv < 10:
                rowStr += " "
            rowStr += str(lv)
        GameWorld.DebugLog("[%s]" % rowStr, curPlayer.GetPlayerID())
    return
def SaveGridData(curPlayer, gridDataList):
    ## 保存行列数据
    for row in range(Def_Size):
        rowDataStr = ""
        for col in range(Def_Size):
            rowDataStr += "%02d" % gridDataList[row][col]
        rowDataValue = int(rowDataStr)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiRowData % row, rowDataValue)
    return
#// AA 25 炼器操作 #tagCMActLianqiOP
#
#struct    tagCMActLianqiOP
#{
#    tagHead        Head;
#    BYTE        OPType;        // 1-移动;2-使用道具;3-重新开始;4-领取等级奖励
#    DWORD        OPValue;        // 移动时-发1上2下3左4右;使用道具时-发使用个数*10+道具ID所在配置索引;等级奖励时-发领取的奖励等级
#    DWORD        OPValue2;    // 使用道具时-发选中格子A的行列值 行*10+列
#    DWORD        OPValue3;    // 使用道具时-发选中格子B的行列值 行*10+列
#};
def OnActLianqiOP(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    playerID = curPlayer.GetPlayerID()
    OPType = clientData.OPType
    OPValue = clientData.OPValue
    OPValue2 = clientData.OPValue2
    OPValue3 = clientData.OPValue3
    if OPType not in [4]:
        actInfo = CrossRealmPlayer.GetPlayerCrossActInfo(curPlayer, ShareDefine.CrossActName_Lianqi)
        if not actInfo:
            GameWorld.DebugLog("非炼器活动中,无法操作! OPType=%s" % OPType, playerID)
            return
        if actInfo.get(ShareDefine.ActKey_StateJoin) != ShareDefine.ActStateJoin_Start:
            GameWorld.DebugLog("非炼器活动参与中,无法操作! OPType=%s" % OPType, playerID)
            return
    if OPType == 1:
        OnMove(curPlayer, OPType, OPValue)
    elif OPType == 2:
        OnUseItem(curPlayer, OPType, OPValue, OPValue2, OPValue3)
    elif OPType == 3:
        ReStartGame(curPlayer, OPType)
    elif OPType == 4:
        OnGetLVAward(curPlayer, OPType, OPValue)
    return
def GetGridLV(r, c, gridDataList):
    ## 获取格子中的图块等级
    # @return: None-越界;0-空位置;>0-对应等级
    if 0 <= r < len(gridDataList) and 0 <= c < len(gridDataList[r]):
        lv = gridDataList[r][c]
        return lv
    return
def OnMove(curPlayer, opType, moveDir):
    ## 移动
    playerID = curPlayer.GetPlayerID()
    curEnergy = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiEnergy)
    if not curEnergy:
        GameWorld.DebugLog("炼器无体力,无法移动!", playerID)
        return
    moveDirCn = ""
    v = [] # 移动行列向量
    if moveDir == 1: # 上
        v = (-1, 0)
        moveDirCn = "上"
    elif moveDir == 2: # 下
        v = (1, 0)
        moveDirCn = "下"
    elif moveDir == 3: # 左
        v = (0, -1)
        moveDirCn = "左"
    elif moveDir == 4: # 右
        v = (0, 1)
        moveDirCn = "右"
    else:
        GameWorld.DebugLog("炼器方向错误,无法移动! moveDir=%s" % moveDir, playerID)
        return
    GameWorld.DebugLog("炼器移动: moveDir=%s%s,v=%s,curEnergy=%s" % (moveDir, moveDirCn, v, curEnergy), playerID)
    gridDataList = GetGridDataList(curPlayer)
    PrintGridData(curPlayer, gridDataList, "移动前")
    vr, vc = v
    loopList = range(Def_Size) if (vr < 0 or vc < 0) else range(Def_Size)[::-1]
    lvUPRCList = [] # 已经升级过的位置列表,每次移动单个位置只能升级一次
    moveList = [] # 移动信息
    addScoreTotal = 0
    for r in loopList:
        for c in loopList:
            lv = GetGridLV(r, c, gridDataList)
            moveTo = []
            if not lv:
                #空位置
                continue
            toR, toC = r, c
            isUp = False
            for _ in range(Def_Size):
                toR += vr
                toC += vc
                if [toR, toC] in lvUPRCList:
                    # 已经升级过的位置视为障碍点, toR, toC
                    break
                lvTo = GetGridLV(toR, toC, gridDataList)
                if lvTo == None:
                    # 超出边界了, toR, toC
                    break
                if not lvTo:
                    moveTo = [toR, toC]
                    isUp = False
                    # 空位置直接替换, toR, toC
                elif lv == lvTo and lv < Def_MaxLV:
                    moveTo = [toR, toC]
                    isUp = True
                    # 可升级, toR, toC
                else:
                    # 其他情况均视为障碍点,被堵住了, toR, toC
                    break
            if moveTo:
                toR, toC = moveTo
                gridDataList[r][c] = 0 # 原位置置空
                if isUp:
                    lv += 1
                    addScore = pow(2, lv)
                    addScoreTotal += addScore
                    GameWorld.DebugLog("合成等级: %s,addScore=%s,addScoreTotal=%s, RC(%s,%s) to (%s,%s)"
                                       % (lv, addScore, addScoreTotal, r, c, toR, toC), playerID)
                    lvUPRCList.append([toR, toC])
                gridDataList[toR][toC] = lv # 替换到新位置
                moveList.append([r, c, toR, toC])
    GameWorld.DebugLog("移动队列: %s" % moveList, playerID)
    if not moveList:
        PlayerControl.NotifyCode(curPlayer, "LianqiMoveUnable")
        return
    # 随机生成新图块
    maxLVNow = 0
    emptyGridList = []
    for row in range(Def_Size):
        for col in range(Def_Size):
            lv = gridDataList[row][col]
            if not lv:
                emptyGridList.append([row, col])
            else:
                if lv >= Def_MaxLV and maxLVNow >= Def_MaxLV:
                    maxLVNow += 1
                else:
                    maxLVNow = max(lv, maxLVNow)
    if emptyGridList:
        row, col = random.choice(emptyGridList)
        randRateList = []
        randRateDict = IpyGameDataPY.GetFuncEvalCfg("LianqiRand", 2, {})
        for lvRange in randRateDict.keys():
            if isinstance(lvRange, tuple) and len(lvRange) == 2 and lvRange[0] <= maxLVNow <= lvRange[1]:
                randRateList = randRateDict[lvRange]
        randLV = GameWorld.GetResultByRandomList(randRateList, 1)
        gridDataList[row][col] = randLV
        GameWorld.DebugLog("随机添加: maxLVNow=%s,row=%s,col=%s,randLV=%s, %s" % (maxLVNow, row, col, randLV, randRateList), playerID)
    PrintGridData(curPlayer, gridDataList, "移动后")
    SetLianqiEnergy(curPlayer, curEnergy - 1)
    AddLianqiScore(curPlayer, addScoreTotal, maxLVNow)
    SaveGridData(curPlayer, gridDataList)
    Sync_LianqiPlayerInfo(curPlayer, opType, moveList)
    return True
def OnUseItem(curPlayer, opType, useInfo, opValue2, opValue3):
    ## 使用辅助道具
    playerID = curPlayer.GetPlayerID()
    itemIDList = IpyGameDataPY.GetFuncEvalCfg("LianqiUseItem", 1)
    useItemCount = max(1, useInfo / 10) # 至少1个
    useIndex = useInfo % 10
    if useIndex < 0 or useIndex >= len(itemIDList):
        GameWorld.DebugLog("炼器辅助道具索引不存在! useIndex=%s" % (useIndex), playerID)
        return
    itemID = itemIDList[useIndex]
    useLimitDict = IpyGameDataPY.GetFuncEvalCfg("LianqiUseItem", 2)
    limitCnt = useLimitDict.get(str(itemID), 0)
    alreadyUsedCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiItemUse % itemID)
    if limitCnt > 0 and alreadyUsedCnt >= limitCnt:
        GameWorld.DebugLog("炼器单局使用该道具次数已达上限! useIndex=%s,itemID=%s,alreadyUsedCnt=%s >= %s" % (useIndex, itemID, alreadyUsedCnt, limitCnt), playerID)
        return
    costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, itemID, useItemCount)
    lackCount = max(0, useItemCount - bindCnt - unBindCnt)
    if lackCount > 0:
        GameWorld.DebugLog("炼器辅助道具不足! useIndex=%s,itemID=%s,lackCount=%s" % (useIndex, itemID, lackCount), playerID)
        return
    rA, cA = opValue2 / 10, opValue2 % 10
    rB, cB = opValue3 / 10, opValue3 % 10
    gridDataList = GetGridDataList(curPlayer)
    # 碎天锤,消除任意位置,且不减分
    if useIndex == 0:
        lvA = GetGridLV(rA, cA, gridDataList)
        if not lvA:
            GameWorld.DebugLog("炼器当前格子不存在或为空,无需使用该道具! useIndex=%s,itemID=%s,rA=%s,cA=%s,lvA=%s" % (useIndex, itemID, rA, cA, lvA), playerID)
            return
        GameWorld.DebugLog("炼器使用消除任意位置道具! useIndex=%s,itemID=%s,rA=%s,cA=%s,lvA=%s" % (useIndex, itemID, rA, cA, lvA), playerID)
        PrintGridData(curPlayer, gridDataList, "使用前")
        gridDataList[rA][cA] = 0
        SaveGridData(curPlayer, gridDataList)
        PrintGridData(curPlayer, gridDataList, "使用后")
    # 造化灵玉,交换任意两个位置
    elif useIndex == 1:
        lvA = GetGridLV(rA, cA, gridDataList)
        lvB = GetGridLV(rB, cB, gridDataList)
        if not lvA or not lvB:
            GameWorld.DebugLog("炼器A或B格子不存在或为空,无需使用该道具! useIndex=%s,itemID=%s,rA=%s,cA=%s,lvA=%s,rB=%s,cB=%s,lvB=%s"
                               % (useIndex, itemID, rA, cA, lvA, rB, cB, lvB), playerID)
            return
        GameWorld.DebugLog("炼器使用交换任意两个位置道具! useIndex=%s,itemID=%s,rA=%s,cA=%s,lvA=%s,rB=%s,cB=%s,lvB=%s"
                               % (useIndex, itemID, rA, cA, lvA, rB, cB, lvB), playerID)
        PrintGridData(curPlayer, gridDataList, "使用前")
        gridDataList[rA][cA] = lvB
        gridDataList[rB][cB] = lvA
        SaveGridData(curPlayer, gridDataList)
        PrintGridData(curPlayer, gridDataList, "使用后")
    # 九天陨铁,将任意1个7阶以下进阶,并获得积分及解锁等级奖励
    elif useIndex == 2:
        lvA = GetGridLV(rA, cA, gridDataList)
        lvLimit = IpyGameDataPY.GetFuncCfg("LianqiUseItem", 3)
        if not lvA or lvA >= lvLimit:
            GameWorld.DebugLog("炼器当前格子不满足使用等级,无需使用该道具! useIndex=%s,itemID=%s,rA=%s,cA=%s,lvA=%s,lvLimit=%s" % (useIndex, itemID, rA, cA, lvA, lvLimit), playerID)
            return
        GameWorld.DebugLog("炼器使用进阶道具! useIndex=%s,itemID=%s,rA=%s,cA=%s,lvA=%s" % (useIndex, itemID, rA, cA, lvA), playerID)
        PrintGridData(curPlayer, gridDataList, "使用前")
        lvA += 1
        gridDataList[rA][cA] = lvA
        SaveGridData(curPlayer, gridDataList)
        PrintGridData(curPlayer, gridDataList, "使用后")
        addScore = pow(2, lvA)
        AddLianqiScore(curPlayer, addScore, lvA)
    # 甘露仙液,体力加15
    elif useIndex == 3:
        curEnergy = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiEnergy)
        energyMax = IpyGameDataPY.GetFuncCfg("LianqiSet", 1)
        if curEnergy >= energyMax:
            GameWorld.DebugLog("炼器体力已满,无需使用该道具! useIndex=%s,itemID=%s,curEnergy=%s >= %s" % (useIndex, itemID, curEnergy, energyMax), playerID)
            return
        addEnergy = IpyGameDataPY.GetFuncCfg("LianqiUseItem", 4) * useItemCount
        updEnergy = curEnergy + addEnergy
        updEnergy = SetLianqiEnergy(curPlayer, updEnergy)
        GameWorld.DebugLog("炼器使用体力道具! useIndex=%s,itemID=%s,useItemCount=%s,addEnergy=%s,curEnergy=%s,updEnergy=%s"
                           % (useIndex, itemID, useItemCount, addEnergy, curEnergy, updEnergy), playerID)
    ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, useItemCount, "Lianqi")
    updUseCnt = alreadyUsedCnt + useItemCount
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiItemUse % itemID, updUseCnt)
    GameWorld.DebugLog("更新单局道具使用次数: useIndex=%s,itemID=%s,updUseCnt=%s" % (useIndex, itemID, updUseCnt), playerID)
    Sync_LianqiPlayerInfo(curPlayer, opType)
    return
def OnProcess(curPlayer):
    if not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_LianqiID):
        return
    curEnergy = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiEnergy)
    energyMax = IpyGameDataPY.GetFuncCfg("LianqiSet", 1)
    if curEnergy >= energyMax:
        #GameWorld.DebugLog("炼器体力已满,无需恢复! curEnergy=%s >= %s" % (curEnergy, energyMax), curPlayer.GetPlayerID())
        return
    needSeconds = IpyGameDataPY.GetFuncCfg("LianqiSet", 2)
    if not needSeconds:
        return
    curTime = int(time.time())
    lastTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiEnergyTime)
    if not lastTime:
        lastTime = curTime
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiEnergyTime, lastTime)
        return
    passTime = curTime - lastTime
    addEnergy = passTime / needSeconds
    if addEnergy <= 0:
        return
    GameWorld.DebugLog("时间恢复炼器体力: passTime=%s(%s-%s),addEnergy=%s" % (passTime, curTime, lastTime, addEnergy), curPlayer.GetPlayerID())
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiEnergyTime, curTime)
    SetLianqiEnergy(curPlayer, min(curEnergy + addEnergy, energyMax))
    Sync_LianqiPlayerInfo(curPlayer)
    return
def SetLianqiEnergy(curPlayer, setEnergy):
    ## 设置炼器体力
    # @param byTime: 由时间恢复的,传入的是当前时间戳
    curEnergy = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiEnergy)
    updEnergy = min(65000, setEnergy)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiEnergy, updEnergy)
    energyMax = IpyGameDataPY.GetFuncCfg("LianqiSet", 1)
    if updEnergy >= energyMax:
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiEnergyTime, 0)
    elif curEnergy >= energyMax and updEnergy < energyMax:
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiEnergyTime, int(time.time()))
    return updEnergy
def AddLianqiScore(curPlayer, addScore, actLV=0):
    ## 增加炼器积分
    if addScore <= 0:
        return
    curScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiScore)
    GameWorld.DebugLog("炼器活动积分增加: curScore=%s,addScore=%s,actLV=%s" % (curScore, addScore, actLV), curPlayer.GetPlayerID())
    SetLianqiScore(curPlayer, curScore + addScore, actLV)
    PlayerZhanling.AddZhanlingValue(curPlayer, PlayerZhanling.ZhanlingType_Lianqi, addScore)
    return
def SetLianqiScore(curPlayer, setScore, actLV=0):
    ## 设置炼器积分
    # @param actLV: 激活的合成等级
    updBillboard = False
    lvHighest = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiLVAwardMax)
    if actLV > lvHighest:
        lvHighest = actLV
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiLVAwardMax, lvHighest)
        updBillboard = True
    updScore = min(setScore, ChConfig.Def_UpperLimit_DWord)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiScore, updScore)
    scoreHighest = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiScoreHighest)
    if updScore > scoreHighest:
        scoreHighest = updScore
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiScoreHighest, scoreHighest)
        updBillboard = True
    GameWorld.DebugLog("炼器活动积分更新: updScore=%s,scoreHighest=%s,lvHighest=%s"
                       % (updScore, scoreHighest, lvHighest), curPlayer.GetPlayerID())
    if updBillboard:
        SendToGameServer_Lianqi(curPlayer, "ScoreHighest", [scoreHighest, lvHighest])
    return updScore
def SendToGameServer_Lianqi(curPlayer, msgType, dataMsg=""):
    playerID = curPlayer.GetPlayerID()
    msgList = str([msgType, dataMsg])
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(playerID, 0, 0, "ActLianqi", msgList, len(msgList))
    GameWorld.Log("炼器活动发送GameServer: %s, %s" % (msgType, dataMsg), playerID)
    return
def OnGetLVAward(curPlayer, opType, awardLV):
    ## 领取炼器等级奖励
    playerID = curPlayer.GetPlayerID()
    curAwardLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiLVAwardMax)
    if curAwardLV < awardLV:
        GameWorld.DebugLog("炼器奖励等级不足! curAwardLV=%s < %s" % (curAwardLV, awardLV), playerID)
        return
    lvAwardItemDict = IpyGameDataPY.GetFuncEvalCfg("LianqiSet", 3, {})
    if str(awardLV) not in lvAwardItemDict:
        return
    awardItemList = lvAwardItemDict[str(awardLV)]
    awardState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiLVAwardState)
    if awardState&pow(2, awardLV):
        GameWorld.DebugLog("炼器奖励等级已领取! awardLV=%s,awardState=%s" % (awardLV, awardState), playerID)
        return
    ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, event=["Lianqi", False, {}])
    updAwardState = awardState|pow(2, awardLV)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_LianqiLVAwardState, updAwardState)
    GameWorld.DebugLog("炼器领取奖励等级! awardLV=%s,awardState=%s,updAwardState=%s,%s"
                       % (awardLV, awardState, updAwardState, awardItemList), playerID)
    Sync_LianqiPlayerInfo(curPlayer, opType)
    return
def Sync_LianqiPlayerInfo(curPlayer, opType=0, moveList=[]):
    if not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CA_LianqiID):
        return
    clientPack = ChPyNetSendPack.tagMCActLianqiPlayerInfo()
    clientPack.Score = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiScore)
    clientPack.ScoreHighest = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiScoreHighest)
    clientPack.Energy = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiEnergy)
    clientPack.EnergyTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiEnergyTime)
    clientPack.LVAwardMax = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiLVAwardMax)
    clientPack.LVAwardState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiLVAwardState)
    clientPack.UseItemCntList = []
    for itemID in IpyGameDataPY.GetFuncEvalCfg("LianqiUseItem", 1):
        clientPack.UseItemCntList.append(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_LianqiItemUse % itemID))
    clientPack.UseItemLen = len(clientPack.UseItemCntList)
    clientPack.GridData = str(GetGridDataList(curPlayer)).replace(" ", "")
    clientPack.GridDataLen = len(clientPack.GridData)
    clientPack.MoveList = []
    for moveInfo in moveList:
        if not isinstance(moveInfo, list) or len(moveInfo) != 4:
            continue
        tileMove = ChPyNetSendPack.tagMCActLianqiTileMove()
        row, col, toRow, toCol = moveInfo
        tileMove.Row = row
        tileMove.Col = col
        tileMove.ToRow = toRow
        tileMove.ToCol = toCol
        clientPack.MoveList.append(tileMove)
    clientPack.OPType = opType
    clientPack.MoveCount = len(clientPack.MoveList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def Sync_CrossActLianqiActionInfo(curPlayer):
    ## 通知活动信息
    actInfo = CrossRealmPlayer.GetPlayerCrossActInfo(curPlayer, ShareDefine.CrossActName_Lianqi)
    if not actInfo:
        return
    if not actInfo.get(ShareDefine.ActKey_State):
        return
    ipyDataDict = actInfo.get(ShareDefine.ActKey_IpyDataInfo, {})
    if not ipyDataDict:
        return
    personalTempID = ipyDataDict.get("PersonalTemplateID", 0)
    personalTempIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActLianqiBillTemp", personalTempID) if personalTempID else []
    clientPack = ChPyNetSendPack.tagMCCrossActLianqiInfo()
    clientPack.ServerIDRangeInfo = str(actInfo.get(ShareDefine.ActKey_ServerIDRangeList, []))
    clientPack.ServerInfoLen = len(clientPack.ServerIDRangeInfo)
    clientPack.GroupValue1 = ipyDataDict.get("ZoneID", 0)
    clientPack.StartDate = ipyDataDict.get("StartDate", "")
    clientPack.EndtDate = ipyDataDict.get("EndDate", "")
    clientPack.JoinStartTime = ipyDataDict.get("JoinStartTime", "")
    clientPack.JoinEndTime = ipyDataDict.get("JoinEndTime", "")
    clientPack.LimitLV = ipyDataDict.get("LimitLV", 0)
    clientPack.PersonalBillboardInfoList = __GetTempRankBillPackList(personalTempIpyDataList)
    clientPack.PersonalBillCount = len(clientPack.PersonalBillboardInfoList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def __GetTempRankBillPackList(ipyDataList):
    packBillList = []
    if not ipyDataList:
        return packBillList
    for tempIpyData in ipyDataList:
        rankInfo = ChPyNetSendPack.tagMCCrossActLianqiBillard()
        rankInfo.Rank = tempIpyData.GetRank()
        rankInfo.AwardItemList = []
        awardItemList = tempIpyData.GetAwardItemList()
        for itemID, itemCount, isAuctionItem in awardItemList:
            item = ChPyNetSendPack.tagMCCrossActLianqiItem()
            item.Clear()
            item.ItemID = itemID
            item.ItemCount = itemCount
            item.IsBind = isAuctionItem
            rankInfo.AwardItemList.append(item)
        rankInfo.Count = len(rankInfo.AwardItemList)
        rankInfo.NeedScore = tempIpyData.GetNeedScore()
#        rankInfo.AwardItemExList = []
#        scoreAwardEx = tempIpyData.GetScoreAwardEx()
#        scoreExList = scoreAwardEx.keys()
#        scoreExList.sort()
#        for scoreEx in scoreExList:
#            itemExList = scoreAwardEx[scoreEx]
#            awardEx = ChPyNetSendPack.tagMCActLianqiAwardEx()
#            awardEx.NeedScore = scoreEx
#            awardEx.AwardItemList = []
#            for itemID, itemCount, isAuctionItem in itemExList:
#                item = ChPyNetSendPack.tagMCActLianqiItem()
#                item.Clear()
#                item.ItemID = itemID
#                item.ItemCount = itemCount
#                item.IsBind = isAuctionItem
#                awardEx.AwardItemList.append(item)
#            awardEx.Count = len(awardEx.AwardItemList)
#
#            rankInfo.AwardItemExList.append(awardEx)
#        rankInfo.CountEx = len(rankInfo.AwardItemExList)
        packBillList.append(rankInfo)
    return packBillList
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -84,6 +84,7 @@
import PlayerActXianXiaMJ
import PlayerActGubao
import PlayerActHorsePetTrain
import PlayerActLianqi
import PlayerActGodGift
import PlayerActFamilyCTGAssist
import PlayerActRechargeRebateGold
@@ -1575,6 +1576,9 @@
            elif actionName == ShareDefine.CrossActName_HorsePetTrain:
                PlayerActHorsePetTrain.RefreshCrossActHorsePetTrainInfo()
                
            elif actionName == ShareDefine.CrossActName_Lianqi:
                PlayerActLianqi.RefreshCrossActLianqiInfo()
            return
        
        if key == ShareDefine.Def_Notify_WorldKey_CrossZoneName:
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
@@ -54,6 +54,7 @@
import FunctionNPCCommon
import FormulaControl
import PlayerGoldGift
import PlayerActLianqi
import PlayerFlashSale
import PlayerChatBox
import PlayerFace
@@ -1297,6 +1298,8 @@
    PlayerActivity.ProcessActivityPlace(curPlayer)
    #自定义场景
    FBLogic.OnCustomSceneProcess(curPlayer, tick)
    #炼器
    PlayerActLianqi.OnProcess(curPlayer)
    #跨服数据同步,放最后
    CrossPlayerData.ProcessCrossPlayer(curPlayer, tick)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerZhanling.py
@@ -42,7 +42,11 @@
ZhanlingType_GubaoTrain, # 古宝养成 8
ZhanlingType_Xianyuan, # 仙缘 9
ZhanlingType_Huanjingge, # 幻境阁 10
) = range(1, 1 + 10)
ZhanlingType_Lianqi, # 炼器 11
) = range(1, 1 + 11)
# 用Value1记录进度的战令类型
ZhanlingValue1TypeList = [ZhanlingType_Huanjingge, ZhanlingType_Lianqi]
def OnPlayerLogin(curPlayer):
    for zhanlingType in ZhanlingTypeList:
@@ -102,6 +106,9 @@
    if zhanlingType == ZhanlingType_Xianyuan:
        backValue = PlayerControl.GetMoney(curPlayer, ShareDefine.TYPE_Price_XianyuanScore)
        PlayerControl.SetMoney(curPlayer, ShareDefine.TYPE_Price_XianyuanScore, 0)
    elif zhanlingType in ZhanlingValue1TypeList:
        backValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ZhanlingValue1 % zhanlingType)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ZhanlingValue1 % zhanlingType, 0)
    GameWorld.Log("重置战令: zhanlingType=%s,backValue=%s,state=(%s to %s) stateH=(%s to %s)" 
                  % (zhanlingType, backValue, state, updState, stateH, updStateH), curPlayer.GetPlayerID())
    
@@ -161,7 +168,7 @@
    return
def AddZhanlingValue(curPlayer, zhanlingType, addValue=1):
    if zhanlingType not in [ZhanlingType_Huanjingge]:
    if zhanlingType not in ZhanlingValue1TypeList:
        return
    curValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ZhanlingValue1 % zhanlingType)
    updValue = min(ChConfig.Def_UpperLimit_DWord, curValue + addValue)
@@ -172,7 +179,7 @@
    return updValue
def SetZhanlingValue(curPlayer, zhanlingType, value1):
    if zhanlingType not in [ZhanlingType_Huanjingge]:
    if zhanlingType not in ZhanlingValue1TypeList:
        return
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ZhanlingValue1 % zhanlingType, value1)
    GameWorld.DebugLog("设置战令进度: zhanlingType=%s,value1=%s" % (zhanlingType, value1), curPlayer.GetPlayerID())
@@ -211,7 +218,7 @@
        curValue = PlayerActGubao.GetActGubaoTrainScore(curPlayer)
    elif zhanlingType == ZhanlingType_Xianyuan:
        curValue = PlayerControl.GetMoney(curPlayer, ShareDefine.TYPE_Price_XianyuanScore)
    elif zhanlingType == ZhanlingType_Huanjingge:
    elif zhanlingType == ZhanlingValue1TypeList:
        curValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ZhanlingValue1 % zhanlingType)
    else:
        return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -363,10 +363,11 @@
CrossActName_XianXiaMJ = "CrossActXianXiaMJ" # 仙匣秘境 - 跨服
CrossActName_Gubao = "CrossActGubao" # 古宝养成 - 跨服
CrossActName_HorsePetTrain = "CrossActHorsePetTrain" # 骑宠养成 - 跨服
CrossActName_Lianqi = "CrossActLianqi" # 炼器 - 跨服
#跨服运营活动列表
CrossActNameList = [CrossActName_CTGBillboard, CrossActName_AllRecharge, CrossActName_LuckyCloudBuy, CrossActName_BossTrial, 
                    CrossActName_XianXiaMJ, CrossActName_Gubao, CrossActName_HorsePetTrain]
                    CrossActName_XianXiaMJ, CrossActName_Gubao, CrossActName_HorsePetTrain, CrossActName_Lianqi]
#需要锁定活动分区分配直到活动结束的跨服运营活动,即使热更分区配置,也不会改变正在活动中的分区设定,直到活动结束
CrossActLockServerGroupIDList = [CrossActName_CTGBillboard, CrossActName_AllRecharge]
@@ -902,7 +903,8 @@
Def_CBT_GubaoScore, # 古宝养成积分 - 个人榜  163
Def_CBT_HorsePetTrainScore, # 骑宠养成积分 - 个人榜  164
Def_CBT_CrossRealmPK, # 跨服PK竞技场  165
) = range(150, 165 + 1)
Def_CBT_LianqiScore, # 炼器积分 - 个人榜  166
) = range(150, 166 + 1)
#职业对应战力排行榜类型
JobFightPowerBillboardDict = {
@@ -1725,6 +1727,7 @@
ClientServerMsg_GubaoScore = "GubaoScore" # 古宝养成积分
ClientServerMsg_HorsePetTrainScore = "HorsePetTrainScore" # 骑宠养成积分
ClientServerMsg_QueryXiangong = "QueryXiangong" # 查看仙宫仙名录
ClientServerMsg_LianqiScore = "LianqiScore" # 炼器积分
#跨服广播类型定义
CrossNotify_CrossAct = "CrossAct"