xdh
2019-04-13 6feb5f6c84521cab58c523d43ba8a8fc02a5029a
6485 【2.0】【后端】炼丹功能开发单
11个文件已修改
1个文件已删除
1007 ■■■■■ 已修改文件
PySysDB/PySysDBPY.h 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py 130 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py 130 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/ClearFruitAttr.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetAlchemyCount.py 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 101 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerAttrFruit.py 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerRefineStove.py 341 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h
@@ -234,7 +234,8 @@
{
    DWORD        _ID;    //物品ID
    BYTE        FuncID;    //所属功能ID
    WORD        MaxUseCnt;    //最大可使用数量
    dict        MaxUseCnt;    //境界对应最大可使用数量
    list        AddItemInfo;    //[增幅丹ID,单次物品数量,单次增加上限]
    WORD        RecycleMoney;    //回收货币值
    DWORD        FightPowerEx;    //附加战斗力
};
@@ -849,35 +850,34 @@
{
    BYTE    _StoveLV;    //炼丹炉等级
    DWORD    UpNeedExp;    //升下一级所需经验
    list    AddAttrType;    //等级加成属性类型
    list    AddAttrNum;    //等级加成属性值
};
//炼丹表
struct tagAlchemy
{
    WORD    _AlchemyID;    //炼丹编号
    dict    Material;    //所需所有材料和数量
    DWORD   _ID;    //秘方唯一ID不可变更
    DWORD   AlchemItemID;    //丹药物品ID
    BYTE    AlchemType;    //秘方类型1-灵丹 2-仙丹
    BYTE    AlchemyQuality;    //秘方品级
    DWORD   LearnNeedItemID;    //丹方物品ID
    BYTE    LearnNeedAlchemLV;    //丹方需要炼丹等级
    WORD    LearnNeedLuck;    //丹方需要慧根
    WORD    NeedTime;    //炼丹时间(秒)
    WORD    AlchemyExp; //炼丹获得经验值
    list    AlchemyItem;    //产出物品及数量及权重
    list    SpecAlchemyID;    //特殊炼丹ID组
    list    AlchemyUp;    //产出包含的进阶丹药
    BYTE    NeedAlchemyLV;    //所需炼丹等级
    dict    Material;    //炼丹材料
};
//炼丹特殊产出表
//炼丹数量表
struct tagAlchemySpec
struct tagAlchemyResult
{
    WORD    _SpecAlchemyID;    //特殊炼丹ID
    DWORD    MaterialID;    //特殊材料ID
    BYTE    MaterialCnt;    //特殊材料ID消耗个数
    WORD    AlchemyExp; //特殊材料经验
    list    AlchemyItem;    //产出物品及数量及权重
    BYTE    NeedAlchemyLV;    //所需炼丹等级
    BYTE    _AlchemyQuality;    //丹方等级
    DWORD    LuckValue;    //慧根
    list    CntRateList;    //数量饼图
};
//BOSS信息表
struct tagBOSSInfo
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -5584,6 +5584,58 @@
#------------------------------------------------------
# A3 17 增加果实使用上限 #tagCMAddFruitUseLimit
class  tagCMAddFruitUseLimit(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("ItemID", c_int),    #果实物品ID
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xA3
        self.SubCmd = 0x17
        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 = 0xA3
        self.SubCmd = 0x17
        self.ItemID = 0
        return
    def GetLength(self):
        return sizeof(tagCMAddFruitUseLimit)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// A3 17 增加果实使用上限 //tagCMAddFruitUseLimit:
                                Cmd:%s,
                                SubCmd:%s,
                                ItemID:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.ItemID
                                )
        return DumpString
m_NAtagCMAddFruitUseLimit=tagCMAddFruitUseLimit()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMAddFruitUseLimit.Cmd,m_NAtagCMAddFruitUseLimit.SubCmd))] = m_NAtagCMAddFruitUseLimit
#------------------------------------------------------
# A3 07 过期物品续费 #tagCMItemRenew
class  tagCMItemRenew(Structure):
@@ -10120,8 +10172,8 @@
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("RefineNum", c_ushort),    # 配方编号
                  ("UseRateItem", c_int),    # 附加材料ID
                  ("AlchemyID", c_int),    # 丹药ID
                  ("DoType", c_ubyte),    # 0-学习 1-开始炼丹 2-停止炼丹 3-开炉取丹
                  ]
    def __init__(self):
@@ -10138,8 +10190,8 @@
    def Clear(self):
        self.Cmd = 0xA5
        self.SubCmd = 0x76
        self.RefineNum = 0
        self.UseRateItem = 0
        self.AlchemyID = 0
        self.DoType = 0
        return
    def GetLength(self):
@@ -10152,14 +10204,14 @@
        DumpString = '''// A5 76 玩家炼丹 //tagCMPlayerRefine:
                                Cmd:%s,
                                SubCmd:%s,
                                RefineNum:%d,
                                UseRateItem:%d
                                AlchemyID:%d,
                                DoType:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.RefineNum,
                                self.UseRateItem
                                self.AlchemyID,
                                self.DoType
                                )
        return DumpString
ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
@@ -12389,6 +12389,7 @@
    _fields_ = [
                  ("ItemID", c_int),    #果实物品ID
                  ("EatCnt", c_ushort),    #已使用个数
                  ("AddItemCnt", c_int),    #增幅丹使用个数
                  ]
    def __init__(self):
@@ -12403,6 +12404,7 @@
    def Clear(self):
        self.ItemID = 0
        self.EatCnt = 0
        self.AddItemCnt = 0
        return
    def GetLength(self):
@@ -12414,11 +12416,13 @@
    def OutputString(self):
        DumpString = '''// A3 39 玩家属性果实已使用个数信息//tagMCAttrFruitEatCntList:
                                ItemID:%d,
                                EatCnt:%d
                                EatCnt:%d,
                                AddItemCnt:%d
                                '''\
                                %(
                                self.ItemID,
                                self.EatCnt
                                self.EatCnt,
                                self.AddItemCnt
                                )
        return DumpString
@@ -16160,20 +16164,15 @@
#------------------------------------------------------
# A3 BF 通知客户端炼丹炉信息 #tagMCPlayerStoveMsg
class  tagMCPlayerStoveMsg(Structure):
class  tagMCPlayerStoveInfo(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("StoveLV", c_ubyte),    # 炼丹炉等级
                  ("StoveExp", c_int),    # 炼丹炉经验
                  ("ItemID", c_int),    # 合成物品id
                  ("AlchemyID", c_int),    # 丹 ID
                  ("StartTime", c_int),    # 开始炼的时间
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xA3
        self.SubCmd = 0xBF
        return
    def ReadData(self, stringData, _pos=0, _len=0):
@@ -16182,39 +16181,120 @@
        return _pos + self.GetLength()
    def Clear(self):
        self.Cmd = 0xA3
        self.SubCmd = 0xBF
        self.StoveLV = 0
        self.StoveExp = 0
        self.ItemID = 0
        self.AlchemyID = 0
        self.StartTime = 0
        return
    def GetLength(self):
        return sizeof(tagMCPlayerStoveMsg)
        return sizeof(tagMCPlayerStoveInfo)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// A3 BF 通知客户端炼丹炉信息 //tagMCPlayerStoveMsg:
                                Cmd:%s,
                                SubCmd:%s,
                                StoveLV:%d,
                                StoveExp:%d,
                                ItemID:%d
                                AlchemyID:%d,
                                StartTime:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.AlchemyID,
                                self.StartTime
                                )
        return DumpString
class  tagMCPlayerStoveMsg(Structure):
    Head = tagHead()
    StoveLV = 0    #(BYTE StoveLV)// 炼丹炉等级
    StoveExp = 0    #(DWORD StoveExp)// 炼丹炉经验
    ItemID = 0    #(DWORD ItemID)// 合成物品id
    ItemCnt = 0    #(BYTE ItemCnt)// 丹药数量
    StoveCnt = 0    #(WORD StoveCnt)// 丹药数量
    InfoList = list()    #(vector<tagMCPlayerStoveInfo> InfoList)
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xA3
        self.Head.SubCmd = 0xBF
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.StoveLV,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.StoveExp,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.ItemID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.ItemCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.StoveCnt,_pos = CommFunc.ReadWORD(_lpData, _pos)
        for i in range(self.StoveCnt):
            temInfoList = tagMCPlayerStoveInfo()
            _pos = temInfoList.ReadData(_lpData, _pos)
            self.InfoList.append(temInfoList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xA3
        self.Head.SubCmd = 0xBF
        self.StoveLV = 0
        self.StoveExp = 0
        self.ItemID = 0
        self.ItemCnt = 0
        self.StoveCnt = 0
        self.InfoList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += 4
        length += 4
        length += 1
        length += 2
        for i in range(self.StoveCnt):
            length += self.InfoList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.StoveLV)
        data = CommFunc.WriteDWORD(data, self.StoveExp)
        data = CommFunc.WriteDWORD(data, self.ItemID)
        data = CommFunc.WriteBYTE(data, self.ItemCnt)
        data = CommFunc.WriteWORD(data, self.StoveCnt)
        for i in range(self.StoveCnt):
            data = CommFunc.WriteString(data, self.InfoList[i].GetLength(), self.InfoList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                StoveLV:%d,
                                StoveExp:%d,
                                ItemID:%d,
                                ItemCnt:%d,
                                StoveCnt:%d,
                                InfoList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.StoveLV,
                                self.StoveExp,
                                self.ItemID
                                self.ItemID,
                                self.ItemCnt,
                                self.StoveCnt,
                                "..."
                                )
        return DumpString
m_NAtagMCPlayerStoveMsg=tagMCPlayerStoveMsg()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCPlayerStoveMsg.Cmd,m_NAtagMCPlayerStoveMsg.SubCmd))] = m_NAtagMCPlayerStoveMsg
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCPlayerStoveMsg.Head.Cmd,m_NAtagMCPlayerStoveMsg.Head.SubCmd))] = m_NAtagMCPlayerStoveMsg
#------------------------------------------------------
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -812,7 +812,7 @@
Writer = xdh
Releaser = xdh
RegType = 0
RegisterPackCount = 2
RegisterPackCount = 3
PacketCMD_1=0xA3
PacketSubCMD_1=0x2B
@@ -822,6 +822,10 @@
PacketSubCMD_2=0x2A
PacketCallFunc_2=OnRecycleAttrFruit
PacketCMD_3=0xA3
PacketSubCMD_3=0x17
PacketCallFunc_3=OnAddFruitUseLimit
;开服活动
[OpenServerCampaign]
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -3468,6 +3468,8 @@
Def_PDict_AddPointValue = "AddPointValue_%s"  # 已加属性点数, 参数(属性ID)
Def_PDict_AttrFruitEatCnt = "AttrFruitEatCnt_%s"  # 已吃属性果实个数,参数为物品id
Def_PDict_AttrFruitAddValue = "AttrFruitAddValue_%s"  # 已吃属性果实增加的属性,参数为物品id
Def_PDict_AttrFruitAddItemCnt = "FruitAddItemCnt_%s"  # 已吃增幅丹个数,参数为果实物品id
Def_PDict_NobleLV = "NobleLV" # 贵族等级, 0位为不同贵族模式版本切换标记位, 从1位开始表示每种等级贵族开通情况, 1-已开通过;9-永久
Def_PDict_NobleEndTime = "NobleEndTime_%s" # 贵族到期结束时间<单位s>, 参数为贵族等级, 从1开始
@@ -3829,9 +3831,11 @@
#炼丹炉
Def_PDict_AlchemyLV = "AlchemyLV" #炼丹等级
Def_PDict_AlchemyExp = "AlchemyExp" #炼丹经验
Def_PDict_AlchemyCount = "AlchemyCount_%s" #特殊炼丹次数产出设定已累计次数, 参数(配方ID)
Def_PDict_AlchemyCountSpec = "AlchemyCountSpec_%s" #特殊炼丹次数产出设定已累计次数, 参数(配方ID)
Def_PDict_AlchemyOutputCount = "AlchemyOutputCount_%s" #炼丹特殊产出物品已产出次数,参数(物品ID)
Def_PDict_AlchemyLearnState = "AlchemyLearnState%s" #丹方是否已学习
Def_PDict_AlchemyItemID = "AlchemyItemID_%s" #炼丹中的丹药ID  参数丹药类型
Def_PDict_AlchemyStartTime = "AlchemyStartTime_%s" #炼丹开始时间    参数丹药ID
Def_PDict_AlchemyPrayCnt = "AlchemyPrayCnt" #炼丹祈福次数
Def_PDict_GFPassiveIndex = "GFP_%s_%s"   # 被动功法 页数-索引
@@ -4272,7 +4276,7 @@
Def_CalcAttrFunc_EquipOutOfPrint, # 绝版属性随等级变化 15
Def_CalcAttrFunc_Success, # 成就属性 16
Def_CalcAttrFunc_VIP, # VIP属性 17
Def_CalcAttrFunc_Stove, # 炼丹炉 18
Def_CalcAttrFunc_Stove, # 炼丹炉 18(废弃)
Def_CalcAttrFunc_FamilyTech, # 仙盟心法 19
Def_CalcAttrFunc_EquipDecompose, # 装备分解属性 20
Def_CalcAttrFunc_PetSoul, # 宠物魂石 21
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -5584,6 +5584,58 @@
#------------------------------------------------------
# A3 17 增加果实使用上限 #tagCMAddFruitUseLimit
class  tagCMAddFruitUseLimit(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("ItemID", c_int),    #果实物品ID
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xA3
        self.SubCmd = 0x17
        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 = 0xA3
        self.SubCmd = 0x17
        self.ItemID = 0
        return
    def GetLength(self):
        return sizeof(tagCMAddFruitUseLimit)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// A3 17 增加果实使用上限 //tagCMAddFruitUseLimit:
                                Cmd:%s,
                                SubCmd:%s,
                                ItemID:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.ItemID
                                )
        return DumpString
m_NAtagCMAddFruitUseLimit=tagCMAddFruitUseLimit()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMAddFruitUseLimit.Cmd,m_NAtagCMAddFruitUseLimit.SubCmd))] = m_NAtagCMAddFruitUseLimit
#------------------------------------------------------
# A3 07 过期物品续费 #tagCMItemRenew
class  tagCMItemRenew(Structure):
@@ -10120,8 +10172,8 @@
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("RefineNum", c_ushort),    # 配方编号
                  ("UseRateItem", c_int),    # 附加材料ID
                  ("AlchemyID", c_int),    # 丹药ID
                  ("DoType", c_ubyte),    # 0-学习 1-开始炼丹 2-停止炼丹 3-开炉取丹
                  ]
    def __init__(self):
@@ -10138,8 +10190,8 @@
    def Clear(self):
        self.Cmd = 0xA5
        self.SubCmd = 0x76
        self.RefineNum = 0
        self.UseRateItem = 0
        self.AlchemyID = 0
        self.DoType = 0
        return
    def GetLength(self):
@@ -10152,14 +10204,14 @@
        DumpString = '''// A5 76 玩家炼丹 //tagCMPlayerRefine:
                                Cmd:%s,
                                SubCmd:%s,
                                RefineNum:%d,
                                UseRateItem:%d
                                AlchemyID:%d,
                                DoType:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.RefineNum,
                                self.UseRateItem
                                self.AlchemyID,
                                self.DoType
                                )
        return DumpString
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -12389,6 +12389,7 @@
    _fields_ = [
                  ("ItemID", c_int),    #果实物品ID
                  ("EatCnt", c_ushort),    #已使用个数
                  ("AddItemCnt", c_int),    #增幅丹使用个数
                  ]
    def __init__(self):
@@ -12403,6 +12404,7 @@
    def Clear(self):
        self.ItemID = 0
        self.EatCnt = 0
        self.AddItemCnt = 0
        return
    def GetLength(self):
@@ -12414,11 +12416,13 @@
    def OutputString(self):
        DumpString = '''// A3 39 玩家属性果实已使用个数信息//tagMCAttrFruitEatCntList:
                                ItemID:%d,
                                EatCnt:%d
                                EatCnt:%d,
                                AddItemCnt:%d
                                '''\
                                %(
                                self.ItemID,
                                self.EatCnt
                                self.EatCnt,
                                self.AddItemCnt
                                )
        return DumpString
@@ -16160,20 +16164,15 @@
#------------------------------------------------------
# A3 BF 通知客户端炼丹炉信息 #tagMCPlayerStoveMsg
class  tagMCPlayerStoveMsg(Structure):
class  tagMCPlayerStoveInfo(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("StoveLV", c_ubyte),    # 炼丹炉等级
                  ("StoveExp", c_int),    # 炼丹炉经验
                  ("ItemID", c_int),    # 合成物品id
                  ("AlchemyID", c_int),    # 丹 ID
                  ("StartTime", c_int),    # 开始炼的时间
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0xA3
        self.SubCmd = 0xBF
        return
    def ReadData(self, stringData, _pos=0, _len=0):
@@ -16182,39 +16181,120 @@
        return _pos + self.GetLength()
    def Clear(self):
        self.Cmd = 0xA3
        self.SubCmd = 0xBF
        self.StoveLV = 0
        self.StoveExp = 0
        self.ItemID = 0
        self.AlchemyID = 0
        self.StartTime = 0
        return
    def GetLength(self):
        return sizeof(tagMCPlayerStoveMsg)
        return sizeof(tagMCPlayerStoveInfo)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''// A3 BF 通知客户端炼丹炉信息 //tagMCPlayerStoveMsg:
                                Cmd:%s,
                                SubCmd:%s,
                                StoveLV:%d,
                                StoveExp:%d,
                                ItemID:%d
                                AlchemyID:%d,
                                StartTime:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.AlchemyID,
                                self.StartTime
                                )
        return DumpString
class  tagMCPlayerStoveMsg(Structure):
    Head = tagHead()
    StoveLV = 0    #(BYTE StoveLV)// 炼丹炉等级
    StoveExp = 0    #(DWORD StoveExp)// 炼丹炉经验
    ItemID = 0    #(DWORD ItemID)// 合成物品id
    ItemCnt = 0    #(BYTE ItemCnt)// 丹药数量
    StoveCnt = 0    #(WORD StoveCnt)// 丹药数量
    InfoList = list()    #(vector<tagMCPlayerStoveInfo> InfoList)
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0xA3
        self.Head.SubCmd = 0xBF
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.StoveLV,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.StoveExp,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.ItemID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.ItemCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.StoveCnt,_pos = CommFunc.ReadWORD(_lpData, _pos)
        for i in range(self.StoveCnt):
            temInfoList = tagMCPlayerStoveInfo()
            _pos = temInfoList.ReadData(_lpData, _pos)
            self.InfoList.append(temInfoList)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0xA3
        self.Head.SubCmd = 0xBF
        self.StoveLV = 0
        self.StoveExp = 0
        self.ItemID = 0
        self.ItemCnt = 0
        self.StoveCnt = 0
        self.InfoList = list()
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 1
        length += 4
        length += 4
        length += 1
        length += 2
        for i in range(self.StoveCnt):
            length += self.InfoList[i].GetLength()
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteBYTE(data, self.StoveLV)
        data = CommFunc.WriteDWORD(data, self.StoveExp)
        data = CommFunc.WriteDWORD(data, self.ItemID)
        data = CommFunc.WriteBYTE(data, self.ItemCnt)
        data = CommFunc.WriteWORD(data, self.StoveCnt)
        for i in range(self.StoveCnt):
            data = CommFunc.WriteString(data, self.InfoList[i].GetLength(), self.InfoList[i].GetBuffer())
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                StoveLV:%d,
                                StoveExp:%d,
                                ItemID:%d,
                                ItemCnt:%d,
                                StoveCnt:%d,
                                InfoList:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.StoveLV,
                                self.StoveExp,
                                self.ItemID
                                self.ItemID,
                                self.ItemCnt,
                                self.StoveCnt,
                                "..."
                                )
        return DumpString
m_NAtagMCPlayerStoveMsg=tagMCPlayerStoveMsg()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCPlayerStoveMsg.Cmd,m_NAtagMCPlayerStoveMsg.SubCmd))] = m_NAtagMCPlayerStoveMsg
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCPlayerStoveMsg.Head.Cmd,m_NAtagMCPlayerStoveMsg.Head.SubCmd))] = m_NAtagMCPlayerStoveMsg
#------------------------------------------------------
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/ClearFruitAttr.py
@@ -79,7 +79,7 @@
                curPlayer.SetDict(attrKey, 0)
                
            if isGiveFruitItem:
                giveFruitItemList.append([itemID, ipyData.GetMaxUseCnt()])
                giveFruitItemList.append([itemID, PlayerAttrFruit.GetMaxEatCnt(curPlayer, itemID)])
                
    PlayerAttrFruit.Sync_AttrFruitEatCnt(curPlayer)
    
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetAlchemyCount.py
File was deleted
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -205,7 +205,8 @@
                "AttrFruit":(
                        ("DWORD", "ID", 1),
                        ("BYTE", "FuncID", 0),
                        ("WORD", "MaxUseCnt", 0),
                        ("dict", "MaxUseCnt", 0),
                        ("list", "AddItemInfo", 0),
                        ("WORD", "RecycleMoney", 0),
                        ("DWORD", "FightPowerEx", 0),
                        ),
@@ -698,27 +699,25 @@
                "RefineStove":(
                        ("BYTE", "StoveLV", 1),
                        ("DWORD", "UpNeedExp", 0),
                        ("list", "AddAttrType", 0),
                        ("list", "AddAttrNum", 0),
                        ),
                "Alchemy":(
                        ("WORD", "AlchemyID", 1),
                        ("dict", "Material", 0),
                        ("DWORD", "ID", 1),
                        ("DWORD", "AlchemItemID", 0),
                        ("BYTE", "AlchemType", 0),
                        ("BYTE", "AlchemyQuality", 0),
                        ("DWORD", "LearnNeedItemID", 0),
                        ("BYTE", "LearnNeedAlchemLV", 0),
                        ("WORD", "LearnNeedLuck", 0),
                        ("WORD", "NeedTime", 0),
                        ("WORD", "AlchemyExp", 0),
                        ("list", "AlchemyItem", 0),
                        ("list", "SpecAlchemyID", 0),
                        ("list", "AlchemyUp", 0),
                        ("BYTE", "NeedAlchemyLV", 0),
                        ("dict", "Material", 0),
                        ),
                "AlchemySpec":(
                        ("WORD", "SpecAlchemyID", 1),
                        ("DWORD", "MaterialID", 0),
                        ("BYTE", "MaterialCnt", 0),
                        ("WORD", "AlchemyExp", 0),
                        ("list", "AlchemyItem", 0),
                        ("BYTE", "NeedAlchemyLV", 0),
                "AlchemyResult":(
                        ("BYTE", "AlchemyQuality", 1),
                        ("DWORD", "LuckValue", 0),
                        ("list", "CntRateList", 0),
                        ),
                "BOSSInfo":(
@@ -1781,14 +1780,16 @@
    def __init__(self):
        self.ID = 0
        self.FuncID = 0
        self.MaxUseCnt = 0
        self.MaxUseCnt = {}
        self.AddItemInfo = []
        self.RecycleMoney = 0
        self.FightPowerEx = 0
        return
        
    def GetID(self): return self.ID # 物品ID
    def GetFuncID(self): return self.FuncID # 所属功能ID
    def GetMaxUseCnt(self): return self.MaxUseCnt # 最大可使用数量
    def GetMaxUseCnt(self): return self.MaxUseCnt # 境界对应最大可使用数量
    def GetAddItemInfo(self): return self.AddItemInfo # [增幅丹ID,单次物品数量,单次增加上限]
    def GetRecycleMoney(self): return self.RecycleMoney # 回收货币值
    def GetFightPowerEx(self): return self.FightPowerEx # 附加战斗力
@@ -2805,54 +2806,50 @@
    def __init__(self):
        self.StoveLV = 0
        self.UpNeedExp = 0
        self.AddAttrType = []
        self.AddAttrNum = []
        return
        
    def GetStoveLV(self): return self.StoveLV # 炼丹炉等级
    def GetUpNeedExp(self): return self.UpNeedExp # 升下一级所需经验
    def GetAddAttrType(self): return self.AddAttrType # 等级加成属性类型
    def GetAddAttrNum(self): return self.AddAttrNum # 等级加成属性值
# 炼丹表
class IPY_Alchemy():
    
    def __init__(self):
        self.AlchemyID = 0
        self.Material = {}
        self.ID = 0
        self.AlchemItemID = 0
        self.AlchemType = 0
        self.AlchemyQuality = 0
        self.LearnNeedItemID = 0
        self.LearnNeedAlchemLV = 0
        self.LearnNeedLuck = 0
        self.NeedTime = 0
        self.AlchemyExp = 0
        self.AlchemyItem = []
        self.SpecAlchemyID = []
        self.AlchemyUp = []
        self.NeedAlchemyLV = 0
        self.Material = {}
        return
        
    def GetAlchemyID(self): return self.AlchemyID # 炼丹编号
    def GetMaterial(self): return self.Material # 所需所有材料和数量
    def GetID(self): return self.ID # 秘方唯一ID不可变更
    def GetAlchemItemID(self): return self.AlchemItemID # 丹药物品ID
    def GetAlchemType(self): return self.AlchemType # 秘方类型1-灵丹 2-仙丹
    def GetAlchemyQuality(self): return self.AlchemyQuality # 秘方品级
    def GetLearnNeedItemID(self): return self.LearnNeedItemID # 丹方物品ID
    def GetLearnNeedAlchemLV(self): return self.LearnNeedAlchemLV # 丹方需要炼丹等级
    def GetLearnNeedLuck(self): return self.LearnNeedLuck # 丹方需要慧根
    def GetNeedTime(self): return self.NeedTime # 炼丹时间(秒)
    def GetAlchemyExp(self): return self.AlchemyExp # 炼丹获得经验值
    def GetAlchemyItem(self): return self.AlchemyItem # 产出物品及数量及权重
    def GetSpecAlchemyID(self): return self.SpecAlchemyID # 特殊炼丹ID组
    def GetAlchemyUp(self): return self.AlchemyUp # 产出包含的进阶丹药
    def GetNeedAlchemyLV(self): return self.NeedAlchemyLV # 所需炼丹等级
    def GetMaterial(self): return self.Material # 炼丹材料
# 炼丹特殊产出表
class IPY_AlchemySpec():
# 炼丹数量表
class IPY_AlchemyResult():
    
    def __init__(self):
        self.SpecAlchemyID = 0
        self.MaterialID = 0
        self.MaterialCnt = 0
        self.AlchemyExp = 0
        self.AlchemyItem = []
        self.NeedAlchemyLV = 0
        self.AlchemyQuality = 0
        self.LuckValue = 0
        self.CntRateList = []
        return
        
    def GetSpecAlchemyID(self): return self.SpecAlchemyID # 特殊炼丹ID
    def GetMaterialID(self): return self.MaterialID # 特殊材料ID
    def GetMaterialCnt(self): return self.MaterialCnt # 特殊材料ID消耗个数
    def GetAlchemyExp(self): return self.AlchemyExp # 特殊材料经验
    def GetAlchemyItem(self): return self.AlchemyItem # 产出物品及数量及权重
    def GetNeedAlchemyLV(self): return self.NeedAlchemyLV # 所需炼丹等级
    def GetAlchemyQuality(self): return self.AlchemyQuality # 丹方等级
    def GetLuckValue(self): return self.LuckValue # 慧根
    def GetCntRateList(self): return self.CntRateList # 数量饼图
# BOSS信息表
class IPY_BOSSInfo():
@@ -4467,8 +4464,8 @@
        self.ipyRefineStoveLen = len(self.ipyRefineStoveCache)
        self.ipyAlchemyCache = self.__LoadFileData("Alchemy", IPY_Alchemy)
        self.ipyAlchemyLen = len(self.ipyAlchemyCache)
        self.ipyAlchemySpecCache = self.__LoadFileData("AlchemySpec", IPY_AlchemySpec)
        self.ipyAlchemySpecLen = len(self.ipyAlchemySpecCache)
        self.ipyAlchemyResultCache = self.__LoadFileData("AlchemyResult", IPY_AlchemyResult)
        self.ipyAlchemyResultLen = len(self.ipyAlchemyResultCache)
        self.ipyBOSSInfoCache = self.__LoadFileData("BOSSInfo", IPY_BOSSInfo)
        self.ipyBOSSInfoLen = len(self.ipyBOSSInfoCache)
        self.ipyElderGodAreaCache = self.__LoadFileData("ElderGodArea", IPY_ElderGodArea)
@@ -4921,8 +4918,8 @@
    def GetRefineStoveByIndex(self, index): return self.ipyRefineStoveCache[index]
    def GetAlchemyCount(self): return self.ipyAlchemyLen
    def GetAlchemyByIndex(self, index): return self.ipyAlchemyCache[index]
    def GetAlchemySpecCount(self): return self.ipyAlchemySpecLen
    def GetAlchemySpecByIndex(self, index): return self.ipyAlchemySpecCache[index]
    def GetAlchemyResultCount(self): return self.ipyAlchemyResultLen
    def GetAlchemyResultByIndex(self, index): return self.ipyAlchemyResultCache[index]
    def GetBOSSInfoCount(self): return self.ipyBOSSInfoLen
    def GetBOSSInfoByIndex(self, index): return self.ipyBOSSInfoCache[index]
    def GetElderGodAreaCount(self): return self.ipyElderGodAreaLen
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerAttrFruit.py
@@ -98,7 +98,7 @@
        if not ipyData:
            continue
        
        maxEatCnt = ipyData.GetMaxUseCnt()
        maxEatCnt = GetMaxEatCnt(curPlayer, itemID)
        eatCntKey = ChConfig.Def_PDict_AttrFruitEatCnt % itemID
        limitType = Def_LimitType_Cnt
        if limitType == Def_LimitType_Attr:
@@ -216,7 +216,7 @@
    funcIndex = ipyData.GetFuncID()
    limitType = Def_LimitType_Cnt
    maxEatCnt = ipyData.GetMaxUseCnt()
    maxEatCnt = GetMaxEatCnt(curPlayer, itemID)
    
    if funcIndex not in ShareDefine.Def_AttrFruitFuncList:
        GameWorld.ErrLog("该属性果实功能未开放!funcIndex=%s"%funcIndex)
@@ -446,7 +446,7 @@
        eatCntPack.Clear()
        eatCntPack.ItemID = fruitItemID
        eatCntPack.EatCnt = curPlayer.NomalDictGetProperty(eatCntKey)
        #eatCntPack.AddAttr = curPlayer.NomalDictGetProperty(addValueKey)
        eatCntPack.AddItemCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AttrFruitAddItemCnt % fruitItemID)
        eatPack.EatCntList.append(eatCntPack)
    
    eatPack.count = len(eatPack.EatCntList)
@@ -480,11 +480,7 @@
def IsFruitEatFull(curPlayer, itemID):
    #使用次数是否已满
    ipyData = GetAttrFruitIpyData(itemID)
    if not ipyData:
        return
    maxEatCnt = ipyData.GetMaxUseCnt()
    maxEatCnt = GetMaxEatCnt(curPlayer, itemID)
    eatCntKey = ChConfig.Def_PDict_AttrFruitEatCnt % itemID
    limitType = Def_LimitType_Cnt
    if limitType == Def_LimitType_Attr:
@@ -493,3 +489,55 @@
    if eatCnt >= maxEatCnt:
        return True
    return
def GetMaxEatCnt(curPlayer, itemID):
    ##获取果实最大可用个数
    ipyData = GetAttrFruitIpyData(itemID)
    if not ipyData:
        return 0
    maxEatCntDict = ipyData.GetMaxUseCnt()
    realmLV = curPlayer.GetOfficialRank()
    orderList = sorted(maxEatCntDict.keys(), reverse=True)
    maxEatCnt = 0
    for order in orderList:
        if realmLV >= order:
            maxEatCnt = maxEatCntDict[order]
            break
    addItemUseCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AttrFruitAddItemCnt % itemID)
    if addItemUseCnt:
        addItemInfo = ipyData.GetAddItemInfo()
        if addItemInfo:
            singleItemCnt, singleAddCnt = addItemInfo[1:]
            maxEatCnt += (addItemUseCnt/singleItemCnt*singleAddCnt)
    return maxEatCnt
#// A3 17 增加果实使用上限 #tagCMAddFruitUseLimit
#
#struct    tagCMAddFruitUseLimit
#{
#    tagHead        Head;
#    DWORD        ItemID;        //果实物品ID
#};
def OnAddFruitUseLimit(index, packData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    itemID = packData.ItemID
    ipyData = GetAttrFruitIpyData(itemID)
    if not ipyData:
        return
    addItemInfo = ipyData.GetAddItemInfo()
    if not addItemInfo:
        return
    addItemUseCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AttrFruitAddItemCnt % itemID)
    needItemID, singleItemCnt, singleAddCnt = addItemInfo
    if addItemUseCnt + singleItemCnt> ChConfig.Def_UpperLimit_DWord:
        return
    itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
    enough, indexList, hasBind, lackCnt = ItemCommon.GetItem_FromPack_ByID_ExEx(needItemID, itemPack, singleItemCnt)
    if not enough:
        return
    ItemCommon.ReduceItem(curPlayer, itemPack, indexList, singleItemCnt, False, "AddFruitUseLimit")
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AttrFruitAddItemCnt % itemID, addItemUseCnt+singleItemCnt)
    Sync_AttrFruitEatCnt(curPlayer, [itemID])
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerRefineStove.py
@@ -6,13 +6,13 @@
##@package PlayerRefineStove
# @todo: 玩家炼丹炉
#
# @author: sgj
# @date 2017-11-07
# @author: xdh
# @date 2019-4-12
# @version 1.0
#
# @note: 
#---------------------------------------------------------------------
#"""Version = 2017-11-07 16:40"""
#"""Version = 2019-4-12 16:40"""
#---------------------------------------------------------------------
import ChConfig
import GameWorld
@@ -35,6 +35,9 @@
import PlayerVip
import copy
import time
DefStoveTypeList = [1, 2]  #1灵丹 2仙丹
##功能开启
@@ -44,24 +47,27 @@
    Sycn_AlchemyMsg(curPlayer)
    return True
##登录处理
def DoOnLogin(curPlayer, tick):
    Sycn_AlchemyMsg(curPlayer)
    Sycn_AlchemyPrayMsg(curPlayer)
    return
def OnDay(curPlayer):
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyPrayCnt, 0)
    Sycn_AlchemyPrayMsg(curPlayer)
    return
#// A5 76 玩家炼丹 #tagCMPlayerRefine
#
#struct tagCMPlayerRefine
#{
#    tagHead    Head;
#    WORD    RefineNum;    // 配方编号
#    DWORD   UseRateItem;  // 附加材料ID
#    DWORD    AlchemyID;    // 丹药ID
#    BYTE   DoType;  // 0-学习 1-开始炼丹 2-停止炼丹 3-开炉取丹
#};
def PlayerRefineItem(index, clientPack, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
@@ -70,193 +76,147 @@
        GameWorld.DebugLog("炼丹炉功能未开启!", playerID)
        return
    
    alchemyID = clientPack.RefineNum
    specID = clientPack.UseRateItem # 特殊炼丹ID
    GameWorld.DebugLog("玩家炼丹: alchemyID=%s,specID=%s" % (alchemyID, specID), playerID)
    alchemyID = clientPack.AlchemyID
    doType = clientPack.DoType
    GameWorld.DebugLog("玩家炼丹: alchemyID=%s, doType=%s" % (alchemyID, doType), playerID)
    alchemyIpyData = IpyGameDataPY.GetIpyGameData("Alchemy", alchemyID)
    if not alchemyIpyData:
        GameWorld.DebugLog("配方不存在!alchemyID=%s" % alchemyID, playerID)
        return
    specAlchemyIpyData = None
    if specID:
        specAlchemyIDList = alchemyIpyData.GetSpecAlchemyID()
        if specID not in specAlchemyIDList:
            GameWorld.DebugLog("非法特殊配方!alchemyID=%s,specID=%s" % (alchemyID, specID), playerID)
            return
        specAlchemyIpyData = IpyGameDataPY.GetIpyGameData("AlchemySpec", specID)
        if not specAlchemyIpyData:
            GameWorld.DebugLog("特殊配方不存在!alchemyID=%s,specID=%s" % (alchemyID, specID), playerID)
            return
    # 等级判断
    alchemType = alchemyIpyData.GetAlchemType()
    alchemyItemID = alchemyIpyData.GetAlchemItemID()
    hasLearn = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_AlchemyLearnState, alchemyID)
    alchemyLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyLV)
    if alchemyLV < alchemyIpyData.GetNeedAlchemyLV():
        GameWorld.DebugLog("配方未开启!alchemyID=%s,needAlchemyLV=%s,curAlchemyLV=%s"
                           % (alchemyID, alchemyIpyData.GetNeedAlchemyLV(), alchemyLV), playerID)
    curAlchemyItemID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyItemID % alchemType)  #正在炼的丹
    curLuckValue = curPlayer.GetLuckValue()
    curTime = int(time.time())
    if doType == 0:
        if hasLearn:
            GameWorld.DebugLog('丹方已学习!,不可重复学')
        return
    if specAlchemyIpyData:
        if alchemyLV < specAlchemyIpyData.GetNeedAlchemyLV():
            GameWorld.DebugLog("特殊配方未开启!alchemyID=%s,specID=%s,needAlchemyLV=%s,curAlchemyLV=%s"
                               % (alchemyID, specID, specAlchemyIpyData.GetNeedAlchemyLV(), alchemyLV), playerID)
        learnNeedAlchemLV = alchemyIpyData.GetLearnNeedAlchemLV()
        if alchemyLV < learnNeedAlchemLV:
            GameWorld.DebugLog('丹方学习需要炼丹等级 %s' % learnNeedAlchemLV)
            return
        alchemyItemList = specAlchemyIpyData.GetAlchemyItem()
        alchemyCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyCountSpec % specID)
        SpecialAlchemyDict = IpyGameDataPY.GetFuncEvalCfg("SpecialAlchemy", 2)
        SpecialAlchemyCountItemDict = SpecialAlchemyDict.get(specID, {})
    else:
        alchemyItemList = alchemyIpyData.GetAlchemyItem()
        alchemyCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyCount % alchemyID)
        SpecialAlchemyDict = IpyGameDataPY.GetFuncEvalCfg("SpecialAlchemy", 1)
        SpecialAlchemyCountItemDict = SpecialAlchemyDict.get(alchemyID, {})
    updAlchemyCount = 0
    if SpecialAlchemyCountItemDict:
        nextAlchemyCount = alchemyCount + 1
        if nextAlchemyCount <= max(SpecialAlchemyCountItemDict):
            updAlchemyCount = nextAlchemyCount # 只要还没达到最大洗练次数特殊产出,则每次累加次数
            # 非特殊材料配方的情况下,达到指定次数则使用特殊次数指定产出库
            if nextAlchemyCount in SpecialAlchemyCountItemDict:
                alchemyItemList = SpecialAlchemyCountItemDict[nextAlchemyCount]
                GameWorld.DebugLog("炼丹次数特殊产出库: 炼丹编号=%s,特殊ID=%s,次数=%s,特殊产出库=%s"
                                   % (alchemyID, specID, nextAlchemyCount, alchemyItemList), playerID)
    # 去除限制产出的物品
    outPutCountLimitDict = IpyGameDataPY.GetFuncEvalCfg("SpecialAlchemy", 3)
    if outPutCountLimitDict:
        limitItemInfoList = []
        alchemyItemList = copy.copy(alchemyItemList)
        for itemInfo in alchemyItemList:
            itemID = itemInfo[1]
            if itemID not in outPutCountLimitDict:
                continue
            limitCount = outPutCountLimitDict[itemID]
            outputCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyOutputCount % itemID)
            if outputCount >= limitCount:
                limitItemInfoList.append(itemInfo)
                GameWorld.DebugLog("已达到最大产出次数,从产出库中移除! alchemyItemList=%s,itemID=%s,outputCount=%s,limitCount=%s"
                                   % (alchemyItemList, itemID, outputCount, limitCount), playerID)
        for limitItemInfo in limitItemInfoList:
            alchemyItemList.remove(limitItemInfo)
    if not alchemyItemList:
        GameWorld.DebugLog("配方产出物品配置错误!alchemyID=%s,specID=%s" % (alchemyID, specID), playerID)
        learnNeedLuck = alchemyIpyData.GetLearnNeedLuck()
        if curLuckValue < learnNeedLuck:
            GameWorld.DebugLog('丹方学习需要慧根 %s' % learnNeedLuck)
        return
    packSpace = ItemCommon.GetItemPackSpace(curPlayer, IPY_GameWorld.rptItem, 1)
    if not packSpace:
        PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_998371")
        learnNeedItemID = alchemyIpyData.GetLearnNeedItemID()
        itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
        enough, indexList, hasBind, lackCnt = ItemCommon.GetItem_FromPack_ByID_ExEx(learnNeedItemID, itemPack, 1)
        if not enough:
        return
        ItemCommon.ReduceItem(curPlayer, itemPack, indexList, 1, False, "RefineStove")
        GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_AlchemyLearnState, alchemyID, 1)
        Sycn_AlchemyMsg(curPlayer, alchemyID, False)
    elif doType == 1:
        if not hasLearn:
            GameWorld.DebugLog('丹方未学习!,不可炼丹')
            return
        if curAlchemyItemID:
            GameWorld.DebugLog('当前丹类型已在炼丹中! curAlchemyItemID=%s' % curAlchemyItemID)
            return
    # 基础固定消耗
    needMaterialDict = alchemyIpyData.GetMaterial()
    # 特殊配方额外消耗
    if specAlchemyIpyData:
        needMaterialDict = copy.deepcopy(needMaterialDict)
        needMaterialDict[specAlchemyIpyData.GetMaterialID()] = specAlchemyIpyData.GetMaterialCnt()
        
    itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
    lackItemDict, delInfoDict = ItemCommon.GetCostItemIndexList(needMaterialDict, itemPack, False)
    if lackItemDict:
        GameWorld.DebugLog("配方材料不足!alchemyID=%s,specID=%s,needMaterialDict=%s,lackItemDict=%s,hasItemDict=%s"
                           % (alchemyID, specID, needMaterialDict, lackItemDict, delInfoDict), playerID)
            GameWorld.DebugLog("配方材料不足!alchemyID=%s,needMaterialDict=%s,lackItemDict=%s,hasItemDict=%s"
                               % (alchemyItemID, needMaterialDict, lackItemDict, delInfoDict), playerID)
        return
        #扣消耗
        ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, ChConfig.ItemDel_Alchemy)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyItemID % alchemType, alchemyItemID)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyStartTime % alchemyID, curTime)
    
    makeItemInfo = GameWorld.GetResultByWeightList(alchemyItemList)
    if not makeItemInfo:
        GameWorld.ErrLog("配方合成结果错误!alchemyID=%s,specID=%s" % (alchemyID, specID), playerID)
        Sycn_AlchemyMsg(curPlayer, alchemyID, False)
        #日常任务
        costItemCnt = sum(needMaterialDict.values())
        PlayerActivity.AddDailyActionFinishCnt(curPlayer, ShareDefine.DailyActionID_RefineStove, costItemCnt)
    elif doType == 2:
        if curAlchemyItemID != alchemyItemID:
            GameWorld.DebugLog('停止丹药ID错误 curAlchemyItemID=%s' % curAlchemyItemID)
        return
    makeItemID, itemCount = makeItemInfo
    GameWorld.DebugLog("合成配方: alchemyID=%s,specID=%s,makeItemID=%s,itemCount=%s,alchemyItemList=%s"
                       % (alchemyID, specID, makeItemID, itemCount, alchemyItemList), playerID)
    #检查按丹炉等级进阶的丹药
    makeItemID = __GetAlchemyUpItemID(makeItemID, alchemyLV, alchemyIpyData.GetAlchemyUp())
    makeItemData = GameWorld.GetGameData().GetItemByTypeID(makeItemID)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyItemID % alchemType, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyStartTime % alchemyID, 0)
        Sycn_AlchemyMsg(curPlayer, alchemyID, False)
    elif doType == 3:
        if curAlchemyItemID != alchemyItemID:
            GameWorld.DebugLog('开炉丹药ID错误 curAlchemyItemID=%s' % curAlchemyItemID)
            return
        startTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyStartTime % alchemyID)
        passTime = max(0, curTime - startTime)
        if passTime < alchemyIpyData.GetNeedTime():
            GameWorld.DebugLog('开炉丹药,时间未到  passTime=%s' % passTime)
            return
        #成功率
        if alchemType == 2:
            successRate = ShareDefine.Def_MaxRateValue  #仙丹必定成功
        else:
            #灵丹成功率公式 参数 curLuckValue:慧根  alchemyLV:炼丹等级 alchemyQuality:丹药等级  qualityNeedLuck:要求慧根
            alchemyQuality = alchemyIpyData.GetAlchemyQuality()
            qualityNeedLuck = IpyGameDataPY.GetFuncEvalCfg('alchemySuccess', 2, {}).get(alchemyQuality, 0)
            successRate = eval(IpyGameDataPY.GetFuncCompileCfg('alchemySuccess'))
        isSuccess = GameWorld.CanHappen(successRate)
        resultCnt = 0  #丹药数量 0代表失败
        if isSuccess:
            needSpace = 1
            packSpace = ItemCommon.GetItemPackSpace(curPlayer, IPY_GameWorld.rptItem, needSpace)
            if needSpace > packSpace:
                PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_998371")
                return
            ipyData = IpyGameDataPY.InterpolationSearch('AlchemyResult', 'LuckValue', curLuckValue, {'AlchemyQuality':alchemyIpyData.GetAlchemyQuality()})
            if not ipyData:
                GameWorld.ErrLog('AlchemyResult 配置错误 未找到该丹方数量 alchemyItemID=%s' % alchemyItemID, playerID)
                return
            resultCnt = GameWorld.GetResultByRandomList(ipyData.GetCntRateList())
            if not resultCnt:
                GameWorld.ErrLog('AlchemyResult 配置错误 未随机出该丹方数量alchemyItemID=%s' % alchemyItemID, playerID)
                return
            makeItemData = GameWorld.GetGameData().GetItemByTypeID(alchemyItemID)
    if not makeItemData:
        return
    if updAlchemyCount:
        if specID:
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyCountSpec % specID, updAlchemyCount)
        else:
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyCount % alchemyID, updAlchemyCount)
        GameWorld.DebugLog("更新炼丹次数累计: alchemyID=%s,特殊ID=%s,次数=%s" % (alchemyID, specID, updAlchemyCount), playerID)
    #扣消耗
    delItemHasBind = ItemCommon.DelCostItem(curPlayer, itemPack, delInfoDict, ChConfig.ItemDel_Alchemy)
    #加经验
    addExp = alchemyIpyData.GetAlchemyExp()
    if specAlchemyIpyData:
        addExp += specAlchemyIpyData.GetAlchemyExp()
    AddRefineExp(curPlayer, addExp)
    #加产出次数
    if makeItemID in outPutCountLimitDict:
        outputCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyOutputCount % makeItemID) + 1
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyOutputCount % makeItemID, outputCount)
        GameWorld.DebugLog("更新炼丹产出特殊物品次数: makeItemID=%s,outputCount=%s" % (makeItemID, outputCount), playerID)
    #给物品
    notBindItemList = IpyGameDataPY.GetFuncEvalCfg("SpecialAlchemy", 4) # 固定不绑定的物品
    if makeItemID in notBindItemList:
        makeItemBind = False
    else:
        makeItemBind = delItemHasBind
    ItemControler.GivePlayerItem(curPlayer, makeItemID, itemCount, 0, [IPY_GameWorld.rptItem],
            ItemControler.GivePlayerItem(curPlayer, alchemyItemID, resultCnt, 0, [IPY_GameWorld.rptItem],
                                 event=[ChConfig.ItemGive_Refine, False, {}])
    Sycn_AlchemyMsg(curPlayer, makeItemID)
    #紫色及以上全服广播
    notifyColor = IpyGameDataPY.GetFuncCfg("AlchemyNotify", 1)
    needNotifyItemIDList = IpyGameDataPY.GetFuncEvalCfg("AlchemyNotify", 2)
    notNotifyItemIDList = IpyGameDataPY.GetFuncEvalCfg("AlchemyNotify", 3)
    if makeItemID not in notNotifyItemIDList and (makeItemID in needNotifyItemIDList or makeItemData.GetItemColor() >= notifyColor):
        PlayerControl.WorldNotify(0, "AchemyGreatSuccess", [curPlayer.GetPlayerName(), makeItemID])
            if alchemyItemID not in notNotifyItemIDList and (alchemyItemID in needNotifyItemIDList or makeItemData.GetItemColor() >= notifyColor):
                PlayerControl.WorldNotify(0, "AchemyGreatSuccess", [curPlayer.GetPlayerName(), alchemyItemID])
        #重置
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyItemID % alchemType, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyStartTime % alchemyID, 0)
        #加经验
        addExp = alchemyIpyData.GetAlchemyExp()
        AddRefineExp(curPlayer, addExp, alchemyLV)
        GameWorld.DebugLog('炼丹结果 alchemyItemID=%s,successRate=%s,isSuccess=%s,resultCnt=%s' % (alchemyItemID, successRate, isSuccess, resultCnt), playerID)
        Sycn_AlchemyMsg(curPlayer, alchemyID, False, alchemyItemID, resultCnt)
        
    #完成1次炼丹成就
    PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_RefineItem, 1)
    #完成1次X品质物品炼丹成就
    PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_RefineStoveColor, 1, [makeItemData.GetItemColor()])
        #PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_RefineStoveColor, 1, [makeItemData.GetItemColor()])
    #任务
    EventShell.EventRespons_RefineItem(curPlayer, alchemyIpyData.GetNeedAlchemyLV())
    #日常任务
    costItemCnt = sum(needMaterialDict.values())
    PlayerActivity.AddDailyActionFinishCnt(curPlayer, ShareDefine.DailyActionID_RefineStove, costItemCnt)
        #EventShell.EventRespons_RefineItem(curPlayer, alchemyIpyData.GetNeedAlchemyLV())
    PlayerFairyCeremony.AddFCPartyActionCnt(curPlayer, ChConfig.Def_PPAct_RefineStove, 1)
    PlayerNewFairyCeremony.AddFCPartyActionCnt(curPlayer, ChConfig.Def_PPAct_RefineStove, 1)
    PlayerActLogin.AddLoginAwardActionCnt(curPlayer, ChConfig.Def_LoginAct_Alchemy, 1)
    return 
def __GetAlchemyUpItemID(itemID, alchemyLV, alchemyUpCfg):
    #获取按丹炉等级进阶的丹药ID
    if not alchemyUpCfg:
        return itemID
    itemIDStr = str(itemID)
    upItemList = []
    for alchemyUpItemDict in alchemyUpCfg:
        if itemIDStr in alchemyUpItemDict:
            for upID, upLV in alchemyUpItemDict.items():
                upItemList.append([upLV, int(upID)])
                
    if not upItemList:
        return itemID
    upItemList.sort(reverse=True)
    for upLV, makeItemID in upItemList:
        if alchemyLV >= upLV:
            GameWorld.DebugLog("    获得进阶丹药: itemID=%s to upItemID=%s" % (itemID, makeItemID))
            return makeItemID
    return itemID
def AddRefineExp(curPlayer, addExp):
def AddRefineExp(curPlayer, addExp, alchemyLV):
    #增加炼丹炉经验
    if addExp <= 0:
        return
    
    alchemyLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyLV)
    alchemyExp = min(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyExp) + addExp, ShareDefine.Def_UpperLimit_DWord)
    GameWorld.DebugLog("增加炼丹经验: alchemyLV=%s,addExp=%s,alchemyExp=%s" % (alchemyLV, addExp, alchemyExp), curPlayer.GetPlayerID())
    
@@ -282,34 +242,45 @@
    GameWorld.DebugLog("升级后剩余经验: %s" % alchemyExp, curPlayer.GetPlayerID())
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlchemyLV, alchemyLV)
    PlayerSuccess.UptateSuccessProgress(curPlayer, ShareDefine.SuccType_AlchemyLV, alchemyLV)
    RefreshStoveAttr(curPlayer)
    # 解锁广播
    ipyGameData = IpyGameDataPY.IPY_Data()
    for i in xrange(ipyGameData.GetAlchemyCount()):
        ipyData = ipyGameData.GetAlchemyByIndex(i)
        if alchemyLV == ipyData.GetNeedAlchemyLV():
            PlayerControl.WorldNotify(0, "FurnaceLVUp", [curPlayer.GetPlayerName(), alchemyLV, ipyData.GetAlchemyID()])
            break
    return True
def Sycn_AlchemyMsg(curPlayer, itemID=0):
def Sycn_AlchemyMsg(curPlayer, alchemyID=0, isAll=True, itemID=0, itemCnt=0):
    # 通知客户端炼丹炉信息
    if not itemID and not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_RefineStove):
    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_RefineStove):
        return
    pack = ChPyNetSendPack.tagMCPlayerStoveMsg()
    pack.StoveExp = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyExp)
    pack.StoveLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyLV)
    pack.ItemID = itemID
    pack.ItemCnt = itemCnt
    pack.InfoList = []
    syncItemIDList = []
    if isAll:
        ipyMgr = IpyGameDataPY.IPY_Data()
        for i in xrange(ipyMgr.GetAlchemyCount()):
            ipyData = ipyMgr.GetAlchemyByIndex(i)
            alchemyID = ipyData.GetID()
            if GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_AlchemyLearnState, alchemyID):
                syncItemIDList.append(alchemyID)
    elif alchemyID and GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_AlchemyLearnState, alchemyID):
        syncItemIDList = [alchemyID]
    for alchemyID in syncItemIDList:
        StoveInfo = ChPyNetSendPack.tagMCPlayerStoveInfo()
        StoveInfo.AlchemyID = alchemyID
        StoveInfo.StartTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyStartTime % alchemyID)
        pack.InfoList.append(StoveInfo)
    pack.StoveCnt = len(pack.InfoList)
    NetPackCommon.SendFakePack(curPlayer, pack)
    return
def RefreshStoveAttr(curPlayer):
    CalcStoveAttr(curPlayer)
    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
    return
def CalcStoveAttr(curPlayer):
    # 果实加成
@@ -317,38 +288,7 @@
    fightPowerEx = PlayerAttrFruit.CalcAttrFruitAddAtrr(curPlayer, allAttrYaoList, ShareDefine.Def_AttrFruitFunc_Stove)
    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_StoveYao, allAttrYaoList)
    curPlayer.SetDict(ChConfig.Def_PlayerKey_MFPEx % ShareDefine.Def_MFPType_StoveYao, fightPowerEx)
    allAttrList = [{} for _ in range(4)]
    alchemyLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyLV)
    stoveIpyData = IpyGameDataPY.GetIpyGameData("RefineStove", alchemyLV)
    if stoveIpyData:
        attrTypeList = stoveIpyData.GetAddAttrType()
        attrValueList = stoveIpyData.GetAddAttrNum()
        for i, attrID in enumerate(attrTypeList):
            PlayerControl.CalcAttrDict_Type(attrID, attrValueList[i], allAttrList)
    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_Stove, allAttrList)
    return
g_needAlchemyLVDict = {}
def GetIsCanOutByAlchemyLV(curPlayer, itemID):
    #判断当前丹炉等级是否可产出该丹药
    global g_needAlchemyLVDict
    if not g_needAlchemyLVDict:
        ipyMgr = IpyGameDataPY.IPY_Data()
        for i in xrange(ipyMgr.GetAlchemyCount()):
            ipyData = ipyMgr.GetAlchemyByIndex(i)
            needAlchemyLV = ipyData.GetNeedAlchemyLV()
            itemList = ipyData.GetAlchemyItem()
            for itemInfo in itemList:
                g_needAlchemyLVDict[itemInfo[1]] = needAlchemyLV
        for i in xrange(ipyMgr.GetAlchemySpecCount()):
            ipyData = ipyMgr.GetAlchemySpecByIndex(i)
            needAlchemyLV = ipyData.GetNeedAlchemyLV()
            itemList = ipyData.GetAlchemyItem()
            for itemInfo in itemList:
                g_needAlchemyLVDict[itemInfo[1]] = needAlchemyLV
    return curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyLV) >= g_needAlchemyLVDict.get(itemID, 0)
#// A5 14 祈福丹药 #tagCMPrayElixir
@@ -375,9 +315,9 @@
    newItemInfoList = []
    for itemInfo in alchemyItemList:
        itemID = itemInfo[1]
        if not GetIsCanOutByAlchemyLV(curPlayer, itemID):
            #GameWorld.DebugLog('祈福丹药,炼丹等级未达到,移除产出库!itemID=%s'%itemID)
            continue
#        if not GetIsCanOutByAlchemyLV(curPlayer, itemID):
#            #GameWorld.DebugLog('祈福丹药,炼丹等级未达到,移除产出库!itemID=%s'%itemID)
#            continue
        if PlayerAttrFruit.IsFruitEatFull(curPlayer, itemID):
            #GameWorld.DebugLog('祈福丹药,使用次数已满,移除产出库!itemID=%s'%itemID)
            continue
@@ -404,7 +344,6 @@
                                 event=[ChConfig.ItemGive_Refine, False, {}])
    #GameWorld.DebugLog('makeItemID=%s,newItemInfoList=%s'%(makeItemID, newItemInfoList))
    
    #紫色及以上全服广播
    notifyColor = IpyGameDataPY.GetFuncCfg("AlchemyNotify", 1)
    needNotifyItemIDList = IpyGameDataPY.GetFuncEvalCfg("AlchemyNotify", 2)
@@ -417,7 +356,9 @@
    Sycn_AlchemyPrayMsg(curPlayer, makeItemID)
    return
def Sycn_AlchemyPrayMsg(curPlayer, itemID=0):
    return
    #祈福丹药结果
    if not itemID and not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_RefineStove):
        return