10033 【后端】仙树升级系统及砍树产出规则(仙树系统;砍树基础)
13个文件已修改
3个文件已添加
1214 ■■■■■ 已修改文件
PySysDB/PySysDBPY.h 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetTree.py 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_TreeLVUPTime.py 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCutTree.py 338 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h
@@ -2890,3 +2890,14 @@
    list        FreeRewardItemList;    //免费奖励物品列表 [[物品ID,个数,是否拍品],...]
    list        ZLRewardItemList;    //战令奖励物品列表 [[物品ID,个数,是否拍品],...]
};
//仙树等级表
struct tagTreeLV
{
    BYTE        _TreeLV;    //仙树等级
    DWORD        LVUPNeedMoney;    //升到下一级所需货币数
    DWORD        LVUPNeedTime;    //升级下一级所需所需秒
    list        EquipColorRateList;    //产出装备品质概率列表,[0品质万分率, 1品质万分率, ...]
    list        ExAwardItemRateList;    //每次砍树概率额外产出道具饼图,[[万分率,[物品ID,个数]], ...]
};
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -18235,6 +18235,118 @@
#------------------------------------------------------
# B2 21 玩家砍树 #tagCMCutTree
class  tagCMCutTree(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("CutCount", c_ubyte),    # 砍几次,默认1
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB2
        self.SubCmd = 0x21
        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 = 0xB2
        self.SubCmd = 0x21
        self.CutCount = 0
        return
    def GetLength(self):
        return sizeof(tagCMCutTree)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B2 21 玩家砍树 //tagCMCutTree:
                                Cmd:%s,
                                SubCmd:%s,
                                CutCount:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.CutCount
                                )
        return DumpString
m_NAtagCMCutTree=tagCMCutTree()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMCutTree.Cmd,m_NAtagCMCutTree.SubCmd))] = m_NAtagCMCutTree
#------------------------------------------------------
# B2 22 砍树装备操作 #tagCMCutTreeEquipOP
class  tagCMCutTreeEquipOP(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("ItemIndex", c_ubyte),    # 物品在砍树背包的索引
                  ("OPType", c_ubyte),    # 操作类型:1-替换;2-分解
                  ("AutoDecompose", c_ubyte),    # 替换后是否自动分解原装备:0否1是,仅替换操作下有用
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB2
        self.SubCmd = 0x22
        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 = 0xB2
        self.SubCmd = 0x22
        self.ItemIndex = 0
        self.OPType = 0
        self.AutoDecompose = 0
        return
    def GetLength(self):
        return sizeof(tagCMCutTreeEquipOP)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B2 22 砍树装备操作 //tagCMCutTreeEquipOP:
                                Cmd:%s,
                                SubCmd:%s,
                                ItemIndex:%d,
                                OPType:%d,
                                AutoDecompose:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.ItemIndex,
                                self.OPType,
                                self.AutoDecompose
                                )
        return DumpString
m_NAtagCMCutTreeEquipOP=tagCMCutTreeEquipOP()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMCutTreeEquipOP.Cmd,m_NAtagCMCutTreeEquipOP.SubCmd))] = m_NAtagCMCutTreeEquipOP
#------------------------------------------------------
# B2 12 领取功能系统特权奖励 #tagCMGetFuncSysPrivilegeAward
class  tagCMGetFuncSysPrivilegeAward(Structure):
@@ -18897,6 +19009,58 @@
#------------------------------------------------------
# B2 23 仙树升级 #tagCMTreeLVUP
class  tagCMTreeLVUP(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("Type", c_ubyte),    # 0-开始升级(请求扣除消耗,开始升级倒计时);1-执行升级(倒计时时间到后发送该类型)
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB2
        self.SubCmd = 0x23
        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 = 0xB2
        self.SubCmd = 0x23
        self.Type = 0
        return
    def GetLength(self):
        return sizeof(tagCMTreeLVUP)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B2 23 仙树升级 //tagCMTreeLVUP:
                                Cmd:%s,
                                SubCmd:%s,
                                Type:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.Type
                                )
        return DumpString
m_NAtagCMTreeLVUP=tagCMTreeLVUP()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMTreeLVUP.Cmd,m_NAtagCMTreeLVUP.SubCmd))] = m_NAtagCMTreeLVUP
#------------------------------------------------------
# B3 17 情戒解锁 #tagCMLoveRingUnlock
class  tagCMLoveRingUnlock(Structure):
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
@@ -43182,6 +43182,121 @@
#------------------------------------------------------
# B1 22 砍树结果 #tagMCCutTreeResult
class  tagMCCutTreeExItem(Structure):
    _pack_ = 1
    _fields_ = [
                  ("ItemID", c_int),    # 额外奖励物品ID
                  ("ItemCount", c_ushort),    # 额外奖励物品ID对应个数
                  ]
    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
        return
    def GetLength(self):
        return sizeof(tagMCCutTreeExItem)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B1 22 砍树结果 //tagMCCutTreeResult:
                                ItemID:%d,
                                ItemCount:%d
                                '''\
                                %(
                                self.ItemID,
                                self.ItemCount
                                )
        return DumpString
class  tagMCCutTreeResult(Structure):
    Head = tagHead()
    EquipCount = 0    #(BYTE EquipCount)// 获得装备数量,默认展示在砍树背包中的装备即可,收到该封包前会先收到0704物品刷新
    ExItemCount = 0    #(BYTE ExItemCount)// 额外奖励物品数
    ExItemList = list()    #(vector<tagMCCutTreeExItem> ExItemList)// 额外奖励物品列表
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xB1
        self.Head.SubCmd = 0x22
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.EquipCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.ExItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.ExItemCount):
            temExItemList = tagMCCutTreeExItem()
            _pos = temExItemList.ReadData(_lpData, _pos)
            self.ExItemList.append(temExItemList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xB1
        self.Head.SubCmd = 0x22
        self.EquipCount = 0
        self.ExItemCount = 0
        self.ExItemList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += 1
        for i in range(self.ExItemCount):
            length += self.ExItemList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.EquipCount)
        data = CommFunc.WriteBYTE(data, self.ExItemCount)
        for i in range(self.ExItemCount):
            data = CommFunc.WriteString(data, self.ExItemList[i].GetLength(), self.ExItemList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                EquipCount:%d,
                                ExItemCount:%d,
                                ExItemList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.EquipCount,
                                self.ExItemCount,
                                "..."
                                )
        return DumpString
m_NAtagMCCutTreeResult=tagMCCutTreeResult()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCCutTreeResult.Head.Cmd,m_NAtagMCCutTreeResult.Head.SubCmd))] = m_NAtagMCCutTreeResult
#------------------------------------------------------
# B1 11 功能系统特权信息 #tagMCFuncSysPrivilegeInfoList
class  tagMCFuncSysPrivilegeInfo(Structure):
@@ -43825,6 +43940,66 @@
#------------------------------------------------------
# B1 21 仙树信息 #tagMCTreeInfo
class  tagMCTreeInfo(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("TreeLV", c_ubyte),    # 当前仙树等级
                  ("LVUPState", c_ubyte),    # 0-非升级中;1-升级中
                  ("LVUPRemainTime", c_int),    # 升级剩余时间,秒;当升级中且倒计时为0时可发送B223执行升级包进行升级
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB1
        self.SubCmd = 0x21
        return
    def ReadData(self, stringData, _pos=0, _len=0):
        self.Clear()
        memmove(addressof(self), stringData[_pos:], self.GetLength())
        return _pos + self.GetLength()
    def Clear(self):
        self.Cmd = 0xB1
        self.SubCmd = 0x21
        self.TreeLV = 0
        self.LVUPState = 0
        self.LVUPRemainTime = 0
        return
    def GetLength(self):
        return sizeof(tagMCTreeInfo)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B1 21 仙树信息 //tagMCTreeInfo:
                                Cmd:%s,
                                SubCmd:%s,
                                TreeLV:%d,
                                LVUPState:%d,
                                LVUPRemainTime:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.TreeLV,
                                self.LVUPState,
                                self.LVUPRemainTime
                                )
        return DumpString
m_NAtagMCTreeInfo=tagMCTreeInfo()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCTreeInfo.Cmd,m_NAtagMCTreeInfo.SubCmd))] = m_NAtagMCTreeInfo
#------------------------------------------------------
# B1 20 战令信息 #tagMCZhanlingInfo
class  tagMCZhanling(Structure):
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -1071,7 +1071,8 @@
CDBPlayerRefresh_AtkBackDefRate, # 抗反击概率 250
CDBPlayerRefresh_SuckHPPer, # 吸血比率 251
CDBPlayerRefresh_SuckHPDefPer, # 抗吸血比率 252
) = range(146, 253)
CDBPlayerRefresh_Xiantao, # 仙桃  253
) = range(146, 254)
TYPE_Price_Gold_Paper_Money = 5    # 金钱类型,(先用礼券,再用金子)
TYPE_Price_Family_Contribution = 6 # 战盟贡献度(活跃度转换得来)
@@ -1099,13 +1100,14 @@
TYPE_Price_JiYuan = 37    # 机缘币
TYPE_Price_BTGMYuE = 38    # GM余额
TYPE_Price_SuccessSocre = 39    # 成就积分
TYPE_Price_Xiantao = 40    # 仙桃
#key可用于遍历所有货币,value仅GM相关会用到
MoneyNameDict = {
                 1:"仙玉", 2:"绑玉", 3:"铜钱", 6:"战盟贡献度", 10:"战盟仓库积分", 13:"境界修行点", 14:"符印融合石", 15:"仙盟活跃令", 
                 16:"助战积分", 18:"荣誉", 19:"Boss积分", 23:"符印精华", 24:"符印碎片", 25:"寻宝积分", 26:"集市额度", 27:"丹精", 28:"魂尘", 
                 29:"聚魂碎片", 30:"核心环", 31:"功能特权令", 32:"环保值", 33:"GM令", 34:"古神币", 35:"功德点", 
                 39:"成就积分"
                 39:"成就积分", 40:"仙桃"
                 }
#以下是旧的金钱类型
@@ -1136,6 +1138,7 @@
                           TYPE_Price_GuShenMoney:CDBPlayerRefresh_GuShenMoney,
                           TYPE_Price_GongdePoint:CDBPlayerRefresh_GongdePoint,
                           TYPE_Price_SuccessSocre:CDBPlayerRefresh_SuccessScore,
                           TYPE_Price_Xiantao:CDBPlayerRefresh_Xiantao,
                           }
# 支持负值的货币及对应0418刷新类型
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1869,7 +1869,7 @@
PacketSubCMD_1=0x26
PacketCallFunc_1=OnVisitFairyDomain
;缥缈仙域
;回合攻击
[TurnAttack]
ScriptName = Attack\TurnAttack.py
Writer = hxp
@@ -1880,3 +1880,23 @@
PacketCMD_1=0xB4
PacketSubCMD_1=0x10
PacketCallFunc_1=OnTurnFight
;砍树
[PlayerCutTree]
ScriptName = Player\PlayerCutTree.py
Writer = hxp
Releaser = hxp
RegType = 0
RegisterPackCount = 3
PacketCMD_1=0xB2
PacketSubCMD_1=0x21
PacketCallFunc_1=OnCutTree
PacketCMD_2=0xB2
PacketSubCMD_2=0x22
PacketCallFunc_2=OnCutTreeEquipOP
PacketCMD_3=0xB2
PacketSubCMD_3=0x23
PacketCallFunc_3=OnTreeLVUP
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -906,6 +906,8 @@
Def_PackCnt_TempSwap = 1
#初始化临时存放背包格子数
Def_PackCnt_TempItem = 10
#初始化鉴定背包格子数
Def_PackCnt_Identify = 10
#初始化宠物背包格子数
Def_PackCnt_Pet = 70
#初始化通用宠物装备背包格子数
@@ -1131,6 +1133,7 @@
                                    IPY_GameWorld.rptItem, 
                                    #IPY_GameWorld.rptFineSoulSlot,
                                    IPY_GameWorld.rptAnyWhere, 
                                    IPY_GameWorld.rptIdentify,
                                    #时装背包
                                    #IPY_GameWorld.rptCabinetWeaponCoat, 
                                    #IPY_GameWorld.rptCabinetHorse, 
@@ -4372,6 +4375,12 @@
#自定义奖励
Def_PDict_CustomAwardCanGet = "CustomAwardCanGet_%s" # 是否可领取,参数(key编号)
Def_PDict_CustomAwardGetState = "CustomAwardGetState_%s" # 是否已领取,参数(key编号)
#仙树
Def_PDict_TreeLV = "TreeLV" # 仙树等级
Def_PDict_TreeLVUPState = "TreeLVUPState" # 仙树升级状态;0-未升级;1-升级中
Def_PDict_TreeLVUPRemainTime = "TreeLVUPRemainTime" # 仙树升级剩余时间,秒
Def_PDict_TreeLVUPRefreshTime = "TreeLVUPRefreshTime" # 仙树升级上次刷新时间戳
#-------------------------------------------------------------------------------
#可以从07 41封包购买的背包类型,和对应字典{背包类型:[字典key, 默认格子数]}
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -18235,6 +18235,118 @@
#------------------------------------------------------
# B2 21 玩家砍树 #tagCMCutTree
class  tagCMCutTree(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("CutCount", c_ubyte),    # 砍几次,默认1
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB2
        self.SubCmd = 0x21
        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 = 0xB2
        self.SubCmd = 0x21
        self.CutCount = 0
        return
    def GetLength(self):
        return sizeof(tagCMCutTree)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B2 21 玩家砍树 //tagCMCutTree:
                                Cmd:%s,
                                SubCmd:%s,
                                CutCount:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.CutCount
                                )
        return DumpString
m_NAtagCMCutTree=tagCMCutTree()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMCutTree.Cmd,m_NAtagCMCutTree.SubCmd))] = m_NAtagCMCutTree
#------------------------------------------------------
# B2 22 砍树装备操作 #tagCMCutTreeEquipOP
class  tagCMCutTreeEquipOP(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("ItemIndex", c_ubyte),    # 物品在砍树背包的索引
                  ("OPType", c_ubyte),    # 操作类型:1-替换;2-分解
                  ("AutoDecompose", c_ubyte),    # 替换后是否自动分解原装备:0否1是,仅替换操作下有用
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB2
        self.SubCmd = 0x22
        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 = 0xB2
        self.SubCmd = 0x22
        self.ItemIndex = 0
        self.OPType = 0
        self.AutoDecompose = 0
        return
    def GetLength(self):
        return sizeof(tagCMCutTreeEquipOP)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B2 22 砍树装备操作 //tagCMCutTreeEquipOP:
                                Cmd:%s,
                                SubCmd:%s,
                                ItemIndex:%d,
                                OPType:%d,
                                AutoDecompose:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.ItemIndex,
                                self.OPType,
                                self.AutoDecompose
                                )
        return DumpString
m_NAtagCMCutTreeEquipOP=tagCMCutTreeEquipOP()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMCutTreeEquipOP.Cmd,m_NAtagCMCutTreeEquipOP.SubCmd))] = m_NAtagCMCutTreeEquipOP
#------------------------------------------------------
# B2 12 领取功能系统特权奖励 #tagCMGetFuncSysPrivilegeAward
class  tagCMGetFuncSysPrivilegeAward(Structure):
@@ -18897,6 +19009,58 @@
#------------------------------------------------------
# B2 23 仙树升级 #tagCMTreeLVUP
class  tagCMTreeLVUP(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("Type", c_ubyte),    # 0-开始升级(请求扣除消耗,开始升级倒计时);1-执行升级(倒计时时间到后发送该类型)
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB2
        self.SubCmd = 0x23
        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 = 0xB2
        self.SubCmd = 0x23
        self.Type = 0
        return
    def GetLength(self):
        return sizeof(tagCMTreeLVUP)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B2 23 仙树升级 //tagCMTreeLVUP:
                                Cmd:%s,
                                SubCmd:%s,
                                Type:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.Type
                                )
        return DumpString
m_NAtagCMTreeLVUP=tagCMTreeLVUP()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMTreeLVUP.Cmd,m_NAtagCMTreeLVUP.SubCmd))] = m_NAtagCMTreeLVUP
#------------------------------------------------------
# B3 17 情戒解锁 #tagCMLoveRingUnlock
class  tagCMLoveRingUnlock(Structure):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -43182,6 +43182,121 @@
#------------------------------------------------------
# B1 22 砍树结果 #tagMCCutTreeResult
class  tagMCCutTreeExItem(Structure):
    _pack_ = 1
    _fields_ = [
                  ("ItemID", c_int),    # 额外奖励物品ID
                  ("ItemCount", c_ushort),    # 额外奖励物品ID对应个数
                  ]
    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
        return
    def GetLength(self):
        return sizeof(tagMCCutTreeExItem)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B1 22 砍树结果 //tagMCCutTreeResult:
                                ItemID:%d,
                                ItemCount:%d
                                '''\
                                %(
                                self.ItemID,
                                self.ItemCount
                                )
        return DumpString
class  tagMCCutTreeResult(Structure):
    Head = tagHead()
    EquipCount = 0    #(BYTE EquipCount)// 获得装备数量,默认展示在砍树背包中的装备即可,收到该封包前会先收到0704物品刷新
    ExItemCount = 0    #(BYTE ExItemCount)// 额外奖励物品数
    ExItemList = list()    #(vector<tagMCCutTreeExItem> ExItemList)// 额外奖励物品列表
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xB1
        self.Head.SubCmd = 0x22
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.EquipCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.ExItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        for i in range(self.ExItemCount):
            temExItemList = tagMCCutTreeExItem()
            _pos = temExItemList.ReadData(_lpData, _pos)
            self.ExItemList.append(temExItemList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xB1
        self.Head.SubCmd = 0x22
        self.EquipCount = 0
        self.ExItemCount = 0
        self.ExItemList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += 1
        for i in range(self.ExItemCount):
            length += self.ExItemList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.EquipCount)
        data = CommFunc.WriteBYTE(data, self.ExItemCount)
        for i in range(self.ExItemCount):
            data = CommFunc.WriteString(data, self.ExItemList[i].GetLength(), self.ExItemList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                EquipCount:%d,
                                ExItemCount:%d,
                                ExItemList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.EquipCount,
                                self.ExItemCount,
                                "..."
                                )
        return DumpString
m_NAtagMCCutTreeResult=tagMCCutTreeResult()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCCutTreeResult.Head.Cmd,m_NAtagMCCutTreeResult.Head.SubCmd))] = m_NAtagMCCutTreeResult
#------------------------------------------------------
# B1 11 功能系统特权信息 #tagMCFuncSysPrivilegeInfoList
class  tagMCFuncSysPrivilegeInfo(Structure):
@@ -43825,6 +43940,66 @@
#------------------------------------------------------
# B1 21 仙树信息 #tagMCTreeInfo
class  tagMCTreeInfo(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("TreeLV", c_ubyte),    # 当前仙树等级
                  ("LVUPState", c_ubyte),    # 0-非升级中;1-升级中
                  ("LVUPRemainTime", c_int),    # 升级剩余时间,秒;当升级中且倒计时为0时可发送B223执行升级包进行升级
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xB1
        self.SubCmd = 0x21
        return
    def ReadData(self, stringData, _pos=0, _len=0):
        self.Clear()
        memmove(addressof(self), stringData[_pos:], self.GetLength())
        return _pos + self.GetLength()
    def Clear(self):
        self.Cmd = 0xB1
        self.SubCmd = 0x21
        self.TreeLV = 0
        self.LVUPState = 0
        self.LVUPRemainTime = 0
        return
    def GetLength(self):
        return sizeof(tagMCTreeInfo)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// B1 21 仙树信息 //tagMCTreeInfo:
                                Cmd:%s,
                                SubCmd:%s,
                                TreeLV:%d,
                                LVUPState:%d,
                                LVUPRemainTime:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.TreeLV,
                                self.LVUPState,
                                self.LVUPRemainTime
                                )
        return DumpString
m_NAtagMCTreeInfo=tagMCTreeInfo()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCTreeInfo.Cmd,m_NAtagMCTreeInfo.SubCmd))] = m_NAtagMCTreeInfo
#------------------------------------------------------
# B1 20 战令信息 #tagMCZhanlingInfo
class  tagMCZhanling(Structure):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetTree.py
New file
@@ -0,0 +1,54 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.SetTree
#
# @todo:设置仙树
# @author hxp
# @date 2023-12-13
# @version 1.0
#
# 详细描述: 设置仙树
#
#-------------------------------------------------------------------------------
#"""Version = 2023-12-13 11:00"""
#-------------------------------------------------------------------------------
import ChConfig
import PlayerControl
import PlayerCutTree
import IpyGameDataPY
import GameWorld
import time
## 逻辑实现
#  @param curPlayer
#  @param cmdList 参数列表
#  @return None
def OnExec(curPlayer, cmdList):
    if not cmdList:
        GameWorld.DebugAnswer(curPlayer, "设置仙树: SetTree 等级 剩余时间秒")
        return
    treeLV = cmdList[0]
    remainTime = cmdList[1] if len(cmdList) > 1 else 0
    ipyData = IpyGameDataPY.GetIpyGameData("TreeLV", treeLV)
    if not ipyData:
        GameWorld.DebugAnswer(curPlayer, "不存在该仙树等级: %s" % treeLV)
        return
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLV, treeLV)
    if remainTime:
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPState, 1)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRemainTime, remainTime)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRefreshTime, int(time.time()))
    else:
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPState, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRemainTime, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRefreshTime, 0)
    GameWorld.DebugAnswer(curPlayer, "设置仙树OK: LV:%s 剩余秒:%s" % (treeLV, remainTime))
    PlayerCutTree.SyncTreeInfo(curPlayer)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -2229,6 +2229,14 @@
                        ("list", "FreeRewardItemList", 0),
                        ("list", "ZLRewardItemList", 0),
                        ),
                "TreeLV":(
                        ("BYTE", "TreeLV", 1),
                        ("DWORD", "LVUPNeedMoney", 0),
                        ("DWORD", "LVUPNeedTime", 0),
                        ("list", "EquipColorRateList", 0),
                        ("list", "ExAwardItemRateList", 0),
                        ),
                }
@@ -6854,6 +6862,23 @@
    def GetRewardIndex(self): return self.RewardIndex # 奖励记录索引,0~n,同个战令类型不可重复
    def GetFreeRewardItemList(self): return self.FreeRewardItemList # 免费奖励物品列表 [[物品ID,个数,是否拍品],...]
    def GetZLRewardItemList(self): return self.ZLRewardItemList # 战令奖励物品列表 [[物品ID,个数,是否拍品],...]
# 仙树等级表
class IPY_TreeLV():
    def __init__(self):
        self.TreeLV = 0
        self.LVUPNeedMoney = 0
        self.LVUPNeedTime = 0
        self.EquipColorRateList = []
        self.ExAwardItemRateList = []
        return
    def GetTreeLV(self): return self.TreeLV # 仙树等级
    def GetLVUPNeedMoney(self): return self.LVUPNeedMoney # 升到下一级所需货币数
    def GetLVUPNeedTime(self): return self.LVUPNeedTime # 升级下一级所需所需秒
    def GetEquipColorRateList(self): return self.EquipColorRateList # 产出装备品质概率列表,[0品质万分率, 1品质万分率, ...]
    def GetExAwardItemRateList(self): return self.ExAwardItemRateList # 每次砍树概率额外产出道具饼图,[[万分率,[物品ID,个数]], ...]
def Log(msg, playerID=0, par=0):
@@ -7333,6 +7358,8 @@
        self.ipyCustomAwardLen = len(self.ipyCustomAwardCache)
        self.ipyZhanlingCache = self.__LoadFileData("Zhanling", IPY_Zhanling)
        self.ipyZhanlingLen = len(self.ipyZhanlingCache)
        self.ipyTreeLVCache = self.__LoadFileData("TreeLV", IPY_TreeLV)
        self.ipyTreeLVLen = len(self.ipyTreeLVCache)
        Log("IPY_FuncConfig count=%s" % len(self.ipyFuncConfigDict))
        Log("IPY_DataMgr InitOK!")
        return
@@ -7953,6 +7980,8 @@
    def GetCustomAwardByIndex(self, index): return self.ipyCustomAwardCache[index]
    def GetZhanlingCount(self): return self.ipyZhanlingLen
    def GetZhanlingByIndex(self, index): return self.ipyZhanlingCache[index]
    def GetTreeLVCount(self): return self.ipyTreeLVLen
    def GetTreeLVByIndex(self, index): return self.ipyTreeLVCache[index]
IPYData = IPY_DataMgr()
def IPY_Data(): return IPYData
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ChItem.py
@@ -755,6 +755,8 @@
        pass
    elif itemTypeID == ChConfig.Def_ItemID_VIPExperience:
        callFuncName = "Item_VIPExperience" #VIP体验卡
    elif itemTypeID == IpyGameDataPY.GetFuncEvalCfg("TreeLVUP", 2)[0]:
        callFuncName = "Item_TreeLVUPTime"
        
    if callFuncName == '':
        #//这个物品是一般物品, 返回外层继续处理
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
@@ -2334,7 +2334,7 @@
def SetItemCount(item, cnt, playerID=0, accID=0, playerName=""):
    if not item.IsEmpty():
        itemID = item.GetItemTypeID()
        if cnt > 0 and itemID in ChConfig.Def_TransformItemIDList:
        if cnt > 0 and (itemID in ChConfig.Def_TransformItemIDList or item.GetType() == ChConfig.Def_ItemType_AutoUseMoney):
            item.SetUserAttr(ShareDefine.Def_IudetItemCount, min(cnt, ChConfig.Def_UpperLimit_DWord))
        else:
            item.SetCount(min(cnt, 65535))
@@ -2347,7 +2347,7 @@
            raise
        
def GetItemCount(item):
    if item.GetItemTypeID() in ChConfig.Def_TransformItemIDList:
    if item.GetItemTypeID() in ChConfig.Def_TransformItemIDList or item.GetType() == ChConfig.Def_ItemType_AutoUseMoney:
        return item.GetUserAttr(ShareDefine.Def_IudetItemCount)
    return item.GetCount()
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/Item_TreeLVUPTime.py
New file
@@ -0,0 +1,46 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package UseItem.Item_TreeLVUPTime
#
# @todo:减少仙树升级时间
# @author hxp
# @date 2023-12-13
# @version 1.0
#
# 详细描述: 减少仙树升级时间
#
#-------------------------------------------------------------------------------
#"""Version = 2023-12-13 11:00"""
#-------------------------------------------------------------------------------
import ItemCommon
import IpyGameDataPY
import PlayerCutTree
import ChConfig
##批量使用物品
# @param curPlayer: 玩家实例
# @param curRoleItem: 物品实例
# @param tick: 时间戳
# @param useCnt: 使用个数
# @return:
def BatchUseItem(curPlayer, curRoleItem, tick, useCnt, exData):
    reduceSeconds = IpyGameDataPY.GetFuncEvalCfg("TreeLVUP", 2)[1]
    reduceTime = reduceSeconds * useCnt
    TreeLVBefore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLV)
    LVUPRemainTimeBefore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPRemainTime)
    if not PlayerCutTree.ReduceTreeLVUPTime(curPlayer, reduceTime):
        return
    succCnt = useCnt
    TreeLVAfter = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLV)
    LVUPRemainTimeAfter = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPRemainTime)
    drDict = {"TreeLVBefore":TreeLVBefore, "LVUPRemainTimeBefore":LVUPRemainTimeBefore,
              "TreeLVAfter":TreeLVAfter, "LVUPRemainTimeAfter":LVUPRemainTimeAfter}
    ItemCommon.DelItem(curPlayer, curRoleItem, succCnt, saveDataDict=drDict)
    return True, succCnt
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -151,6 +151,7 @@
import PlayerShentong
import PlayerCustomAward
import PlayerZhanling
import PlayerCutTree
import PlayerLianTi
import PlayerYinji
import PlayerLove
@@ -960,6 +961,7 @@
    PlayerGubao.OnPlayerLogin(curPlayer)
    PlayerShentong.OnPlayerLogin(curPlayer)
    PlayerZhanling.OnPlayerLogin(curPlayer)
    PlayerCutTree.OnPlayerLogin(curPlayer)
    # 上线查询一次充值订单
    curPlayer.SendDBQueryRecharge()
    
@@ -1516,6 +1518,11 @@
    #初始化寻宝背包
    PlayerControl.Init_TreasurePack(curPlayer)
    
    #初始化鉴定背包
    curPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptIdentify)
    curPack.SetCount(ChConfig.Def_PackCnt_Identify)
    curPack.Sync_PackCanUseCount()
    #初始化神兽物品背包
    curPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptDogzItem)
    curPack.SetCount(ChConfig.Def_PackCnt_DogzItem)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCutTree.py
New file
@@ -0,0 +1,338 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Player.PlayerCutTree
#
# @todo:砍树
# @author hxp
# @date 2023-12-13
# @version 1.0
#
# 详细描述: 砍树
#
#-------------------------------------------------------------------------------
#"""Version = 2023-12-13 11:00"""
#-------------------------------------------------------------------------------
import GameWorld
import ItemCommon
import ShareDefine
import NetPackCommon
import IpyGameDataPY
import ChPyNetSendPack
import PlayerControl
import IPY_GameWorld
import ItemControler
import NPCCommon
import ChConfig
import ChEquip
import random
import time
def OnPlayerLogin(curPlayer):
    RefreshTreeLVUPTime(curPlayer)
    SyncTreeInfo(curPlayer)
    return
#// B2 21 玩家砍树 #tagCMCutTree
#
#struct    tagCMCutTree
#{
#    tagHead         Head;
#    BYTE        CutCount;    // 砍几次,默认1
#};
def OnCutTree(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    cutCount = clientData.CutCount
    playerID = curPlayer.GetPlayerID()
    identifyPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptIdentify)
    packCount = identifyPack.GetCount()
    for i in range(0, packCount):
        curItem = identifyPack.GetAt(i)
        if curItem and not curItem.IsEmpty():
            GameWorld.DebugLog("砍树背包中还有未处理物品,无法砍树! i=%s" % i, playerID)
            return
    treeLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLV)
    canCutMax = 0
    lvCutMaxList = IpyGameDataPY.GetFuncEvalCfg("CutTree", 2)
    for curMax, needLV in enumerate(lvCutMaxList, 1):
        if treeLV >= needLV:
            canCutMax = curMax
        else:
            break
    cutCount = min(cutCount, canCutMax, identifyPack.GetCount())
    GameWorld.DebugLog("玩家砍树: cutCount=%s,treeLV=%s,canCutMax=%s,packCount=%s" % (cutCount, treeLV, canCutMax, packCount), playerID)
    if not cutCount:
        return
    if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, cutCount):
        return
    ipyData = IpyGameDataPY.GetIpyGameData("TreeLV", treeLV)
    if not ipyData:
        return
    equipColorRateList = ipyData.GetEquipColorRateList()
    exAwardItemRateList = ipyData.GetExAwardItemRateList()
    GameWorld.DebugLog("    equipColorRateList=%s" % equipColorRateList, playerID)
    maxRate = 10000
    totalRate = 0
    colorRateList = []
    for equipColor, colorRate in enumerate(equipColorRateList):
        if not colorRate:
            continue
        totalRate += colorRate
        colorRateList.append([totalRate, equipColor])
    if totalRate != maxRate:
        GameWorld.SendGameError("GameWarning", "CutTreeTotalRateError:%s!=%s" % (totalRate, maxRate))
    if not colorRateList:
        return
    GameWorld.DebugLog("    colorRateList=%s,totalRate=%s" % (colorRateList, totalRate), playerID)
    playerLV = curPlayer.GetLV()
    classLV = int(playerLV / 50 + 1)
    classLVMax = min(15, classLV + 1)
    classLVMin = max(1, min(classLV - 1, classLVMax - 2))
    classLVList = range(classLVMin, classLVMax + 1)
    GameWorld.DebugLog("    classLVList=%s,playerLV=%s,classLVMin=%s,classLVMax=%s"
                       % (classLVList, playerLV, classLVMin, classLVMax), playerID)
    randEquipIDList = []
    for _ in range(cutCount):
        itemColor = GameWorld.GetResultByRandomList(colorRateList)
        if not itemColor:
            continue
        # 产出装备规则待扩展,先固定
        classLV = random.choice(classLVList)
        isSuit = 0
        placeList = ChConfig.EquipPlace_Base
        jobList = [curPlayer.GetJob()]
        equipIDList = NPCCommon.__GetEquipIDList(0, classLV, itemColor, isSuit, placeList, jobList, findType="CutTree")
        if not equipIDList:
            continue
        randEquipIDList.append(random.choice(equipIDList))
    GameWorld.DebugLog("    预产出装备: randEquipIDList=%s" % randEquipIDList, playerID)
    giveItemListEx = []
    giveEquipIDList = []
    for equipItemID in randEquipIDList:
        curItem = ItemControler.GetOutPutItemObj(equipItemID, 1, False, curPlayer=curPlayer)
        if curItem == None:
            continue
        if not ItemControler.DoLogic_PutItemInPack(curPlayer, curItem, packIndexList=[IPY_GameWorld.rptIdentify]):
            continue
        giveEquipIDList.append(equipItemID)
        exItem = GameWorld.GetResultByRandomList(exAwardItemRateList)
        if exItem:
            giveItemListEx.append([exItem[0], exItem[1], 0])
    if not giveEquipIDList:
        return
    giveEquipCount = len(giveEquipIDList)
    PlayerControl.PayMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, giveEquipCount)
    cutExp = IpyGameDataPY.GetFuncCfg("CutTree", 1)
    addExp = giveEquipCount * cutExp
    if addExp > 0:
        PlayerControl.PlayerControl(curPlayer).AddExp(addExp)
    ItemControler.GivePlayerItemOrMail(curPlayer, giveItemListEx)
    GameWorld.DebugLog("    实际产出: giveEquipIDList=%s,giveItemListEx=%s,addExp=%s" % (giveEquipIDList, giveItemListEx, addExp), playerID)
    SyncCutTreeResult(curPlayer, giveEquipCount, giveItemListEx)
    return
#// B2 22 砍树装备操作 #tagCMCutTreeEquipOP
#
#struct    tagCMCutTreeEquipOP
#{
#    tagHead        Head;
#    BYTE        ItemIndex;    // 物品在砍树背包的索引
#    BYTE        OPType;        // 操作类型:1-替换;2-分解
#    BYTE        AutoDecompose;    // 替换后是否自动分解原装备:0否1是,仅替换操作下有用
#};
def OnCutTreeEquipOP(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    opType = clientData.OPType
    itemIndex = clientData.ItemIndex
    autoDecompose = clientData.AutoDecompose
    playerID = curPlayer.GetPlayerID()
    identifyPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptIdentify)
    if itemIndex >= identifyPack.GetCount():
        GameWorld.DebugLog("砍树背包索引不存在: itemIndex=%s" % itemIndex, playerID)
        return
    curEquip = identifyPack.GetAt(itemIndex)
    if not ItemCommon.CheckItemCanUse(curEquip):
        GameWorld.DebugLog("砍树背包物品不存在: itemIndex=%s" % itemIndex, playerID)
        return
    GameWorld.DebugLog("砍树装备操作: itemIndex=%s,opType=%s,autoDecompose=%s" % (itemIndex, opType, autoDecompose), playerID)
    # 替换
    if opType == 1:
        equipIndex = ItemCommon.GetEquipPackIndex(curEquip)
        if not ChEquip.DoPlayerEquipItem(curPlayer, curEquip, equipIndex, tick):
            return
        if autoDecompose:
            __DoEquipDecompose(curPlayer, identifyPack.GetAt(itemIndex)) # 需重新获得装备对象
    # 分解
    elif opType == 2:
        __DoEquipDecompose(curPlayer, curEquip)
    # 放入备用仓库
    elif opType == 3:
        pass
    else:
        return
    return
def __DoEquipDecompose(curPlayer, curEquip):
    if not curEquip:
        return
    itemID = curEquip.GetItemTypeID()
    playerID = curPlayer.GetPlayerID()
    GameWorld.DebugLog("装备分解: itemID=%s" % (itemID), playerID)
    # 这边执行分解逻辑,待扩展...
    ItemCommon.DelItem(curPlayer, curEquip, curEquip.GetCount(), True, ChConfig.ItemDel_EquipDecompose)
    return
#// B2 23 仙树升级 #tagCMTreeLVUP
#
#struct    tagCMTreeLVUP
#{
#    tagHead         Head;
#    BYTE        Type;    // 0-开始升级(请求扣除消耗,开始升级倒计时);1-执行升级(倒计时时间到后发送该类型)
#};
def OnTreeLVUP(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    upType = clientData.Type
    if upType == 1:
        DoTreeLVUP(curPlayer)
        return
    playerID = curPlayer.GetPlayerID()
    lvupState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPState)
    if lvupState:
        GameWorld.DebugLog("仙树已经在升级中! lvupState=%s" % lvupState, playerID)
        return
    treeLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLV)
    ipyData = IpyGameDataPY.GetIpyGameData("TreeLV", treeLV)
    if not ipyData:
        return
    needMoney = ipyData.GetLVUPNeedMoney()
    nextTreeLV = treeLV + 1
    nextIpyData = IpyGameDataPY.GetIpyGameDataNotLog("TreeLV", nextTreeLV)
    if needMoney <= 0 or not nextIpyData:
        GameWorld.DebugLog("仙树已满级! treeLV=%s" % treeLV, playerID)
        return
    moneyType = IpyGameDataPY.GetFuncCfg("TreeLVUP", 1)
    if not PlayerControl.PayMoney(curPlayer, moneyType, needMoney, "TreeLVUP", {"treeLV":treeLV}):
        return
    needTime = ipyData.GetLVUPNeedTime()
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPState, 1)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRemainTime, needTime)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRefreshTime, int(time.time()))
    GameWorld.DebugLog("仙树请求开始升级! treeLV=%s,nextTreeLV=%s,needTime=%s" % (treeLV, nextTreeLV, needTime), playerID)
    SyncTreeInfo(curPlayer)
    return
def RefreshTreeLVUPTime(curPlayer):
    ## 刷新仙树升级剩余时间
    lvupState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPState)
    LVUPRemainTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPRemainTime)
    if not lvupState or not LVUPRemainTime:
        return
    curTime = int(time.time())
    lastRefreshTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPRefreshTime)
    if not lastRefreshTime:
        lastRefreshTime = curTime
    passSeconds = max(0, curTime - lastRefreshTime)
    updLVUPRemainTime = max(0, LVUPRemainTime - passSeconds)
    treeLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLV)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRemainTime, updLVUPRemainTime)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRefreshTime, curTime)
    GameWorld.DebugLog("刷新仙树升级剩余时间! updLVUPRemainTime=%s,treeLV=%s,LVUPRemainTime=%s,passSeconds=%s,lastRefreshTime=%s"
                       % (updLVUPRemainTime, treeLV, LVUPRemainTime, passSeconds, lastRefreshTime), curPlayer.GetPlayerID())
    return
def ReduceTreeLVUPTime(curPlayer, reduceTime):
    ## 减少仙树升级剩余时间,可能是使用道具或其他功能等
    RefreshTreeLVUPTime(curPlayer)
    lvupState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPState)
    LVUPRemainTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPRemainTime)
    if not lvupState or not LVUPRemainTime:
        GameWorld.DebugLog("仙树非升级中或剩余时间为0,不需要减少时间! lvupState=%s,LVUPRemainTime=%s"
                           % (lvupState, LVUPRemainTime), curPlayer.GetPlayerID())
        return
    updLVUPRemainTime = max(0, LVUPRemainTime - reduceTime)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRemainTime, updLVUPRemainTime)
    GameWorld.DebugLog("减少仙树升级剩余时间! updLVUPRemainTime=%s,LVUPRemainTime=%s,reduceTime=%s"
                       % (updLVUPRemainTime, LVUPRemainTime, reduceTime), curPlayer.GetPlayerID())
    SyncTreeInfo(curPlayer)
    return True
def DoTreeLVUP(curPlayer):
    ## 执行仙树升级
    RefreshTreeLVUPTime(curPlayer)
    playerID = curPlayer.GetPlayerID()
    lvupState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPState)
    if not lvupState:
        GameWorld.DebugLog("仙树非升级中,无法执行升级! lvupState=%s" % lvupState, playerID)
        return
    LVUPRemainTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPRemainTime)
    if LVUPRemainTime > 0:
        GameWorld.DebugLog("仙树升级剩余时间未到,无法执行升级! LVUPRemainTime=%s" % LVUPRemainTime, playerID)
        return
    treeLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLV)
    updTreeLV = treeLV + 1
    ipyData = IpyGameDataPY.GetIpyGameData("TreeLV", updTreeLV)
    if not ipyData:
        return
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLV, updTreeLV)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPState, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRemainTime, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreeLVUPRefreshTime, 0)
    GameWorld.DebugLog("执行仙树升级! updTreeLV=%s" % updTreeLV, playerID)
    SyncTreeInfo(curPlayer)
    return
def SyncTreeInfo(curPlayer):
    clientPack = ChPyNetSendPack.tagMCTreeInfo()
    clientPack.TreeLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLV)
    clientPack.LVUPState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPState)
    clientPack.LVUPRemainTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreeLVUPRemainTime)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def SyncCutTreeResult(curPlayer, equipCount, giveItemListEx):
    clientPack = ChPyNetSendPack.tagMCCutTreeResult()
    clientPack.EquipCount = equipCount
    clientPack.ExItemList = []
    for itemID, itemCount, _ in giveItemListEx:
        item = ChPyNetSendPack.tagMCCutTreeExItem()
        item.ItemID = itemID
        item.ItemCount = itemCount
        clientPack.ExItemList.append(item)
    clientPack.ExItemCount = len(clientPack.ExItemList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -1071,7 +1071,8 @@
CDBPlayerRefresh_AtkBackDefRate, # 抗反击概率 250
CDBPlayerRefresh_SuckHPPer, # 吸血比率 251
CDBPlayerRefresh_SuckHPDefPer, # 抗吸血比率 252
) = range(146, 253)
CDBPlayerRefresh_Xiantao, # 仙桃  253
) = range(146, 254)
TYPE_Price_Gold_Paper_Money = 5    # 金钱类型,(先用礼券,再用金子)
TYPE_Price_Family_Contribution = 6 # 战盟贡献度(活跃度转换得来)
@@ -1099,13 +1100,14 @@
TYPE_Price_JiYuan = 37    # 机缘币
TYPE_Price_BTGMYuE = 38    # GM余额
TYPE_Price_SuccessSocre = 39    # 成就积分
TYPE_Price_Xiantao = 40    # 仙桃
#key可用于遍历所有货币,value仅GM相关会用到
MoneyNameDict = {
                 1:"仙玉", 2:"绑玉", 3:"铜钱", 6:"战盟贡献度", 10:"战盟仓库积分", 13:"境界修行点", 14:"符印融合石", 15:"仙盟活跃令", 
                 16:"助战积分", 18:"荣誉", 19:"Boss积分", 23:"符印精华", 24:"符印碎片", 25:"寻宝积分", 26:"集市额度", 27:"丹精", 28:"魂尘", 
                 29:"聚魂碎片", 30:"核心环", 31:"功能特权令", 32:"环保值", 33:"GM令", 34:"古神币", 35:"功德点", 
                 39:"成就积分"
                 39:"成就积分", 40:"仙桃"
                 }
#以下是旧的金钱类型
@@ -1136,6 +1138,7 @@
                           TYPE_Price_GuShenMoney:CDBPlayerRefresh_GuShenMoney,
                           TYPE_Price_GongdePoint:CDBPlayerRefresh_GongdePoint,
                           TYPE_Price_SuccessSocre:CDBPlayerRefresh_SuccessScore,
                           TYPE_Price_Xiantao:CDBPlayerRefresh_Xiantao,
                           }
# 支持负值的货币及对应0418刷新类型