From e386ca47903c63b59e0db877423c565e295d2cb9 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期四, 06 五月 2021 16:16:50 +0800
Subject: [PATCH] 8721 【主干】【BT2】【后端】H.活动-合服庆典(转盘)

---
 ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py                                  |   35 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py        |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py               |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py               |  143 +++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py           |  309 +++++++++++
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py                                    |  143 +++++
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py                                |  309 +++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActTurntable.py |  541 ++++++++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py             |   56 ++
 PySysDB/PySysDBPY.h                                                                              |   20 
 ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py                                    |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py      |   11 
 PySysDB/PySysDBG.h                                                                               |   13 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                  |   11 
 14 files changed, 1,600 insertions(+), 6 deletions(-)

diff --git a/PySysDB/PySysDBG.h b/PySysDB/PySysDBG.h
index ff76b50..2e8f39a 100644
--- a/PySysDB/PySysDBG.h
+++ b/PySysDB/PySysDBG.h
@@ -638,6 +638,19 @@
 	BYTE		IsDayReset;	//是否每天重置
 };
 
+//转盘活动表
+
+struct tagActTurntable
+{
+	DWORD		_CfgID;	//配置ID
+	list		PlatformList;	//活动平台列表["平台A", "平台A", ...],配[]代表所有
+	list		ServerGroupIDList;	//服务器ID列表
+	BYTE		ActNum;	//活动分组编号, 活动类型 * 10 + 不同界面编号
+	char		StartDate;	//开启日期
+	char		EndDate;	//结束日期
+	BYTE		IsDayReset;	//是否每天重置
+};
+
 //多日连充活动表
 
 struct tagActManyDayRecharge
diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index 09fbff0..e45e5bf 100644
--- a/PySysDB/PySysDBPY.h
+++ b/PySysDB/PySysDBPY.h
@@ -1679,6 +1679,26 @@
 	char 		NotifyKey;	//广播
 };
 
+//转盘活动表
+
+struct tagActTurntable
+{
+	DWORD		_CfgID;	//配置ID
+	char		StartDate;	//开启日期
+	char		EndDate;	//结束日期
+	WORD		LVLimit;	//限制等级
+	BYTE		IsDayReset;	//是否每天重置
+	BYTE		CTGTypeEffValue;	//充值有效类型值
+	list		CTGPrizeList;	//累计充值奖励次数
+	list		UseGoldPrizeList;	//累计消费X仙玉奖励次数
+	list		LibChooseCountList;	//各道具库选择个数
+	list		SuperItemLimitRule;	//终极库产出万分率|至少X次后可产出
+	dict		CommItemLib;	//普通道具库 {(世界等级A,世界等级B):[[可选物品ID, 个数, 是否拍品], ...], ...}
+	dict		GoodItemLib;	//极品道具库 {(世界等级A,世界等级B):[[可选物品ID, 个数, 是否拍品], ...], ...}
+	dict		SuperItemLib;	//超级道具库 {(世界等级A,世界等级B):[[可选物品ID, 个数, 是否拍品], ...], ...}
+	char		WorldNotifyKey;	//好物品全服广播mark,极品及超级道具默认全服广播
+};
+
 //单笔累充活动表
 
 struct tagActSingleRecharge
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
index 650f1b5..7820c45 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -13321,6 +13321,149 @@
 
 
 #------------------------------------------------------
+# AA 12 选择转盘活动物品 #tagCMActTurntableChooseItem
+
+class  tagCMActTurntableChooseItem(Structure):
+    Head = tagHead()
+    ActNum = 0    #(BYTE ActNum)// 活动编号
+    GoodItemNumCount = 0    #(BYTE GoodItemNumCount)
+    GoodItemNumList = list()    #(vector<BYTE> GoodItemNumList)// 选择的极品物品编号列表
+    SuperItemNumCount = 0    #(BYTE SuperItemNumCount)
+    SuperItemNumList = list()    #(vector<BYTE> SuperItemNumList)// 选择的终极物品编号列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x12
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ActNum,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.GoodItemNumCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.GoodItemNumCount):
+            value,_pos=CommFunc.ReadBYTE(_lpData,_pos)
+            self.GoodItemNumList.append(value)
+        self.SuperItemNumCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.SuperItemNumCount):
+            value,_pos=CommFunc.ReadBYTE(_lpData,_pos)
+            self.SuperItemNumList.append(value)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x12
+        self.ActNum = 0
+        self.GoodItemNumCount = 0
+        self.GoodItemNumList = list()
+        self.SuperItemNumCount = 0
+        self.SuperItemNumList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        length += 1 * self.GoodItemNumCount
+        length += 1
+        length += 1 * self.SuperItemNumCount
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ActNum)
+        data = CommFunc.WriteBYTE(data, self.GoodItemNumCount)
+        for i in range(self.GoodItemNumCount):
+            data = CommFunc.WriteBYTE(data, self.GoodItemNumList[i])
+        data = CommFunc.WriteBYTE(data, self.SuperItemNumCount)
+        for i in range(self.SuperItemNumCount):
+            data = CommFunc.WriteBYTE(data, self.SuperItemNumList[i])
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActNum:%d,
+                                GoodItemNumCount:%d,
+                                GoodItemNumList:%s,
+                                SuperItemNumCount:%d,
+                                SuperItemNumList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActNum,
+                                self.GoodItemNumCount,
+                                "...",
+                                self.SuperItemNumCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagCMActTurntableChooseItem=tagCMActTurntableChooseItem()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMActTurntableChooseItem.Head.Cmd,m_NAtagCMActTurntableChooseItem.Head.SubCmd))] = m_NAtagCMActTurntableChooseItem
+
+
+#------------------------------------------------------
+# AA 13 启动转盘 #tagCMActTurntableStart
+
+class  tagCMActTurntableStart(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ActNum", c_ubyte),    # 活动编号
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x13
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xAA
+        self.SubCmd = 0x13
+        self.ActNum = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMActTurntableStart)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 13 启动转盘 //tagCMActTurntableStart:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ActNum:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ActNum
+                                )
+        return DumpString
+
+
+m_NAtagCMActTurntableStart=tagCMActTurntableStart()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMActTurntableStart.Cmd,m_NAtagCMActTurntableStart.SubCmd))] = m_NAtagCMActTurntableStart
+
+
+#------------------------------------------------------
 # AA 07 许愿池活动刷新奖池 #tagCMActWishingRefresh
 
 class  tagCMActWishingRefresh(Structure):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
index 2a5ea16..8f6fbc3 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
@@ -26533,6 +26533,315 @@
 
 
 #------------------------------------------------------
+# AA 52 转盘活动信息 #tagMCActTurntableInfo
+
+class  tagMCActTurntableItem(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("ItemNum", c_ubyte),    #物品编号 1~n;注意转盘已确定物品编号 与 极品终极物品待选择库编号可能相同,但并不代表同一物品
+                  ("ItemLibType", c_ubyte),    #物品库类型;1-常规,2-极品,3-终极
+                  ("ItemID", c_int),    
+                  ("ItemCount", c_ushort),    
+                  ]
+
+    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.ItemNum = 0
+        self.ItemLibType = 0
+        self.ItemID = 0
+        self.ItemCount = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCActTurntableItem)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 52 转盘活动信息 //tagMCActTurntableInfo:
+                                ItemNum:%d,
+                                ItemLibType:%d,
+                                ItemID:%d,
+                                ItemCount:%d
+                                '''\
+                                %(
+                                self.ItemNum,
+                                self.ItemLibType,
+                                self.ItemID,
+                                self.ItemCount
+                                )
+        return DumpString
+
+
+class  tagMCActTurntableInfo(Structure):
+    Head = tagHead()
+    ActNum = 0    #(BYTE ActNum)// 活动编号
+    StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
+    EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
+    IsDayReset = 0    #(BYTE IsDayReset)// 是否每天重置
+    LimitLV = 0    #(WORD LimitLV)// 限制等级
+    CTGPrizeCount = 0    #(BYTE CTGPrizeCount)
+    CTGPrizeList = list()    #(vector<DWORD> CTGPrizeList)// 累计充值额度奖励次数列表 [奖励第1次所需累计充值额度, 第2次, ...]
+    UseGoldPrizeCount = 0    #(BYTE UseGoldPrizeCount)
+    UseGoldPrizeList = list()    #(vector<DWORD> UseGoldPrizeList)// 累计消费仙玉奖励次数列表 [奖励第1次所需累计消费仙玉, 第2次, ...]
+    TurnItemCount = 0    #(BYTE TurnItemCount)
+    TurnItemList = list()    #(vector<tagMCActTurntableItem> TurnItemList)// 转盘已确定的物品列表,包含常规物品+极品物品+终极物品,活动开始时,后端直接随机生成常规物品,已确定的物品不包含极品、终极物品时需要先选择才能使用转盘;
+    GoodItemCount = 0    #(BYTE GoodItemCount)
+    GoodItemList = list()    #(vector<tagMCActTurntableItem> GoodItemList)// 极品物品待选择库,由玩家从库中选择放入转盘的物品;注意此库中的物品编号仅表示在该库中的编号,可能与转盘已确定的物品编号重复,但并不代表同一物品;
+    GoodItemCanChooseCount = 0    #(BYTE GoodItemCanChooseCount)// 极品物品可选择个数
+    SuperItemCount = 0    #(BYTE SuperItemCount)
+    SuperItemList = list()    #(vector<tagMCActTurntableItem> SuperItemList)// 终极物品待选择库,由玩家从库中选择放入转盘的物品;注意此库中的物品编号仅表示在该库中的编号,可能与转盘已确定的物品编号重复,但并不代表同一物品;
+    SuperItemCanChooseCount = 0    #(BYTE SuperItemCanChooseCount)// 终极物品可选择个数
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x52
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ActNum,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
+        self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
+        self.IsDayReset,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.LimitLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.CTGPrizeCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.CTGPrizeCount):
+            value,_pos=CommFunc.ReadDWORD(_lpData,_pos)
+            self.CTGPrizeList.append(value)
+        self.UseGoldPrizeCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.UseGoldPrizeCount):
+            value,_pos=CommFunc.ReadDWORD(_lpData,_pos)
+            self.UseGoldPrizeList.append(value)
+        self.TurnItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.TurnItemCount):
+            temTurnItemList = tagMCActTurntableItem()
+            _pos = temTurnItemList.ReadData(_lpData, _pos)
+            self.TurnItemList.append(temTurnItemList)
+        self.GoodItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.GoodItemCount):
+            temGoodItemList = tagMCActTurntableItem()
+            _pos = temGoodItemList.ReadData(_lpData, _pos)
+            self.GoodItemList.append(temGoodItemList)
+        self.GoodItemCanChooseCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.SuperItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.SuperItemCount):
+            temSuperItemList = tagMCActTurntableItem()
+            _pos = temSuperItemList.ReadData(_lpData, _pos)
+            self.SuperItemList.append(temSuperItemList)
+        self.SuperItemCanChooseCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x52
+        self.ActNum = 0
+        self.StartDate = ""
+        self.EndtDate = ""
+        self.IsDayReset = 0
+        self.LimitLV = 0
+        self.CTGPrizeCount = 0
+        self.CTGPrizeList = list()
+        self.UseGoldPrizeCount = 0
+        self.UseGoldPrizeList = list()
+        self.TurnItemCount = 0
+        self.TurnItemList = list()
+        self.GoodItemCount = 0
+        self.GoodItemList = list()
+        self.GoodItemCanChooseCount = 0
+        self.SuperItemCount = 0
+        self.SuperItemList = list()
+        self.SuperItemCanChooseCount = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 10
+        length += 10
+        length += 1
+        length += 2
+        length += 1
+        length += 4 * self.CTGPrizeCount
+        length += 1
+        length += 4 * self.UseGoldPrizeCount
+        length += 1
+        for i in range(self.TurnItemCount):
+            length += self.TurnItemList[i].GetLength()
+        length += 1
+        for i in range(self.GoodItemCount):
+            length += self.GoodItemList[i].GetLength()
+        length += 1
+        length += 1
+        for i in range(self.SuperItemCount):
+            length += self.SuperItemList[i].GetLength()
+        length += 1
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ActNum)
+        data = CommFunc.WriteString(data, 10, self.StartDate)
+        data = CommFunc.WriteString(data, 10, self.EndtDate)
+        data = CommFunc.WriteBYTE(data, self.IsDayReset)
+        data = CommFunc.WriteWORD(data, self.LimitLV)
+        data = CommFunc.WriteBYTE(data, self.CTGPrizeCount)
+        for i in range(self.CTGPrizeCount):
+            data = CommFunc.WriteDWORD(data, self.CTGPrizeList[i])
+        data = CommFunc.WriteBYTE(data, self.UseGoldPrizeCount)
+        for i in range(self.UseGoldPrizeCount):
+            data = CommFunc.WriteDWORD(data, self.UseGoldPrizeList[i])
+        data = CommFunc.WriteBYTE(data, self.TurnItemCount)
+        for i in range(self.TurnItemCount):
+            data = CommFunc.WriteString(data, self.TurnItemList[i].GetLength(), self.TurnItemList[i].GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.GoodItemCount)
+        for i in range(self.GoodItemCount):
+            data = CommFunc.WriteString(data, self.GoodItemList[i].GetLength(), self.GoodItemList[i].GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.GoodItemCanChooseCount)
+        data = CommFunc.WriteBYTE(data, self.SuperItemCount)
+        for i in range(self.SuperItemCount):
+            data = CommFunc.WriteString(data, self.SuperItemList[i].GetLength(), self.SuperItemList[i].GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.SuperItemCanChooseCount)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActNum:%d,
+                                StartDate:%s,
+                                EndtDate:%s,
+                                IsDayReset:%d,
+                                LimitLV:%d,
+                                CTGPrizeCount:%d,
+                                CTGPrizeList:%s,
+                                UseGoldPrizeCount:%d,
+                                UseGoldPrizeList:%s,
+                                TurnItemCount:%d,
+                                TurnItemList:%s,
+                                GoodItemCount:%d,
+                                GoodItemList:%s,
+                                GoodItemCanChooseCount:%d,
+                                SuperItemCount:%d,
+                                SuperItemList:%s,
+                                SuperItemCanChooseCount:%d
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActNum,
+                                self.StartDate,
+                                self.EndtDate,
+                                self.IsDayReset,
+                                self.LimitLV,
+                                self.CTGPrizeCount,
+                                "...",
+                                self.UseGoldPrizeCount,
+                                "...",
+                                self.TurnItemCount,
+                                "...",
+                                self.GoodItemCount,
+                                "...",
+                                self.GoodItemCanChooseCount,
+                                self.SuperItemCount,
+                                "...",
+                                self.SuperItemCanChooseCount
+                                )
+        return DumpString
+
+
+m_NAtagMCActTurntableInfo=tagMCActTurntableInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActTurntableInfo.Head.Cmd,m_NAtagMCActTurntableInfo.Head.SubCmd))] = m_NAtagMCActTurntableInfo
+
+
+#------------------------------------------------------
+# AA 53 转盘活动玩家信息 #tagMCActTurntablePlayerInfo
+
+class  tagMCActTurntablePlayerInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ActNum", c_ubyte),    #活动编号
+                  ("CanUseCount", c_ubyte),    #可转盘次数
+                  ("CTGTotal", c_int),    #累计充值额度
+                  ("UseGoldTotal", c_int),    #累计消费仙玉额度
+                  ("TurnItemState", c_int),    #转盘物品已抽中记录,按转盘物品编号二进制位代表是否已抽中
+                  ("GetItemNum", c_ubyte),    #本次抽中的物品编号,非转盘结果时为0,大于0时为通知本次转到的物品编号
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x53
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xAA
+        self.SubCmd = 0x53
+        self.ActNum = 0
+        self.CanUseCount = 0
+        self.CTGTotal = 0
+        self.UseGoldTotal = 0
+        self.TurnItemState = 0
+        self.GetItemNum = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCActTurntablePlayerInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 53 转盘活动玩家信息 //tagMCActTurntablePlayerInfo:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ActNum:%d,
+                                CanUseCount:%d,
+                                CTGTotal:%d,
+                                UseGoldTotal:%d,
+                                TurnItemState:%d,
+                                GetItemNum:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ActNum,
+                                self.CanUseCount,
+                                self.CTGTotal,
+                                self.UseGoldTotal,
+                                self.TurnItemState,
+                                self.GetItemNum
+                                )
+        return DumpString
+
+
+m_NAtagMCActTurntablePlayerInfo=tagMCActTurntablePlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActTurntablePlayerInfo.Cmd,m_NAtagMCActTurntablePlayerInfo.SubCmd))] = m_NAtagMCActTurntablePlayerInfo
+
+
+#------------------------------------------------------
 # AA 1B 许愿池拖动结果 #tagMCActWishingDragResult
 
 class  tagMCPlayerWishingDragInfo(Structure):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
index f2df7f2..177cf6b 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
@@ -532,6 +532,16 @@
                         ("BYTE", "IsDayReset", 0),
                         ),
 
+                "ActTurntable":(
+                        ("DWORD", "CfgID", 1),
+                        ("list", "PlatformList", 0),
+                        ("list", "ServerGroupIDList", 0),
+                        ("BYTE", "ActNum", 0),
+                        ("char", "StartDate", 0),
+                        ("char", "EndDate", 0),
+                        ("BYTE", "IsDayReset", 0),
+                        ),
+
                 "ActManyDayRecharge":(
                         ("DWORD", "CfgID", 1),
                         ("list", "PlatformList", 0),
@@ -1768,6 +1778,27 @@
     def GetNotifyInfoLoop(self): return self.NotifyInfoLoop # 全服提示信息 - 循环广播[间隔分钟, 广播key]
     def GetIsDayReset(self): return self.IsDayReset # 是否每天重置
 
+# 转盘活动表
+class IPY_ActTurntable():
+    
+    def __init__(self):
+        self.CfgID = 0
+        self.PlatformList = []
+        self.ServerGroupIDList = []
+        self.ActNum = 0
+        self.StartDate = ""
+        self.EndDate = ""
+        self.IsDayReset = 0
+        return
+        
+    def GetCfgID(self): return self.CfgID # 配置ID
+    def GetPlatformList(self): return self.PlatformList # 活动平台列表["平台A", "平台A", ...],配[]代表所有
+    def GetServerGroupIDList(self): return self.ServerGroupIDList # 服务器ID列表
+    def GetActNum(self): return self.ActNum # 活动分组编号, 活动类型 * 10 + 不同界面编号
+    def GetStartDate(self): return self.StartDate # 开启日期
+    def GetEndDate(self): return self.EndDate # 结束日期
+    def GetIsDayReset(self): return self.IsDayReset # 是否每天重置
+
 # 多日连充活动表
 class IPY_ActManyDayRecharge():
     
@@ -2279,6 +2310,8 @@
         self.ipyActGrowupBuyLen = len(self.ipyActGrowupBuyCache)
         self.ipyActSingleRechargeCache = self.__LoadFileData("ActSingleRecharge", IPY_ActSingleRecharge)
         self.ipyActSingleRechargeLen = len(self.ipyActSingleRechargeCache)
+        self.ipyActTurntableCache = self.__LoadFileData("ActTurntable", IPY_ActTurntable)
+        self.ipyActTurntableLen = len(self.ipyActTurntableCache)
         self.ipyActManyDayRechargeCache = self.__LoadFileData("ActManyDayRecharge", IPY_ActManyDayRecharge)
         self.ipyActManyDayRechargeLen = len(self.ipyActManyDayRechargeCache)
         self.ipyActTotalRechargeCache = self.__LoadFileData("ActTotalRecharge", IPY_ActTotalRecharge)
@@ -2575,6 +2608,8 @@
     def GetActGrowupBuyByIndex(self, index): return self.ipyActGrowupBuyCache[index]
     def GetActSingleRechargeCount(self): return self.ipyActSingleRechargeLen
     def GetActSingleRechargeByIndex(self, index): return self.ipyActSingleRechargeCache[index]
+    def GetActTurntableCount(self): return self.ipyActTurntableLen
+    def GetActTurntableByIndex(self, index): return self.ipyActTurntableCache[index]
     def GetActManyDayRechargeCount(self): return self.ipyActManyDayRechargeLen
     def GetActManyDayRechargeByIndex(self, index): return self.ipyActManyDayRechargeCache[index]
     def GetActTotalRechargeCount(self): return self.ipyActTotalRechargeLen
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
index 22eb365..fc07677 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -234,6 +234,7 @@
 OperationActionName_FeastTravel = "ActFeastTravel" # 节日游历活动
 OperationActionName_ManyDayRecharge = "ActManyDayRecharge" # 多日连充活动
 OperationActionName_SingleRecharge = "ActSingleRecharge" # 单笔累充活动
+OperationActionName_Turntable = "ActTurntable" # 转盘活动
 #节日活动类型列表 - 该类型无视开服天,日期到了就开启
 FeastOperationActionNameList = [OperationActionName_FeastWeekParty, OperationActionName_FeastRedPacket,
                                 OperationActionName_RechargeRebateGold, OperationActionName_GrowupBuy,
@@ -251,6 +252,7 @@
                            OperationActionName_NewFairyCeremony, OperationActionName_LuckyTreasure,
                            OperationActionName_DailyGiftbag, OperationActionName_SingleRecharge,
                            OperationActionName_CollectWords, OperationActionName_ManyDayRecharge,
+                           OperationActionName_Turntable,
                            ] + FeastOperationActionNameList
 #需要记录开启活动时的世界等级的运营活动
 NeedWorldLVOperationActNameList = [OperationActionName_FairyCeremony, OperationActionName_WishingWell, 
@@ -259,7 +261,7 @@
                                    OperationActionName_CostRebate, OperationActionName_FlashGiftbag,
                                    OperationActionName_SpringSale, OperationActionName_LuckyTreasure,
                                    OperationActionName_DailyGiftbag, OperationActionName_GrowupBuy,
-                                   OperationActionName_WeekParty,
+                                   OperationActionName_WeekParty, OperationActionName_Turntable,
                                    OperationActionName_CollectWords,
                                    OperationActionName_FeastLogin,
                                    OperationActionName_FeastWish, OperationActionName_FeastTravel,
@@ -271,6 +273,7 @@
                                    OperationActionName_FlashGiftbag, OperationActionName_CostRebate,
                                    OperationActionName_SpringSale, OperationActionName_FlashSale,
                                    OperationActionName_ManyDayRecharge, OperationActionName_SingleRecharge,
+                                   OperationActionName_Turntable,
                                    ]
 
 #跨服运营活动表名定义
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index 14822b0..f2e6f8e 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -3872,6 +3872,17 @@
 Def_PDict_SingleRechargeWorldLV = "SingleRechargeWorldLV_%s" #玩家身上的活动世界等级,参数:(活动编号)
 Def_PDict_SingleRechargeValue = "SingleRechargeValue_%s"  # 领奖奖励值,按奖励索引二进制位代表是否可领奖,参数:(活动编号)
 Def_PDict_SingleRechargeAward = "SingleRechargeAward_%s"  # 领奖记录值,按奖励索引二进制位代表是否已领奖,参数:(活动编号)
+
+#转盘活动
+Def_PDict_TurntableID = "TurntableID_%s"  # 玩家身上的活动ID,唯一标识,取活动开始日期time值,参数:(活动编号)
+Def_PDict_TurntableWorldLV = "TurntableWorldLV_%s" #玩家身上的活动世界等级,参数:(活动编号)
+Def_PDict_TurntableLoginState = "TurntableLoginState_%s"  # 登录加次数状态,参数:(活动编号)
+Def_PDict_TurntableCTGValue = "TurntableCTGValue_%s"  # 累计充值,参数:(活动编号)
+Def_PDict_TurntableUseGold = "TurntableUseGold_%s"  # 累计消费仙玉,参数:(活动编号)
+Def_PDict_TurntableCanUseCount = "TurntableCanUseCount_%s"  # 可使用转盘次数,参数:(活动编号)
+Def_PDict_TurntableItemID = "TurntableItemID_%s_%s"  # 转盘物品ID*10+物品库类型,参数:(活动编号, 物品编号)
+Def_PDict_TurntableItemCount = "TurntableCount_%s_%s"  # 转盘物品个数,参数:(活动编号, 物品编号)
+Def_PDict_TurntableItemState = "TurntableItemState_%s"  # 转盘物品是否已抽中,按物品编号二进制位代表是否已抽中,参数:(活动编号)
 #-------------------------------------------------------------------------------
 
 #开服活动,Def_PDictType_OpenServerCampaign
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 650f1b5..7820c45 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -13321,6 +13321,149 @@
 
 
 #------------------------------------------------------
+# AA 12 选择转盘活动物品 #tagCMActTurntableChooseItem
+
+class  tagCMActTurntableChooseItem(Structure):
+    Head = tagHead()
+    ActNum = 0    #(BYTE ActNum)// 活动编号
+    GoodItemNumCount = 0    #(BYTE GoodItemNumCount)
+    GoodItemNumList = list()    #(vector<BYTE> GoodItemNumList)// 选择的极品物品编号列表
+    SuperItemNumCount = 0    #(BYTE SuperItemNumCount)
+    SuperItemNumList = list()    #(vector<BYTE> SuperItemNumList)// 选择的终极物品编号列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x12
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ActNum,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.GoodItemNumCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.GoodItemNumCount):
+            value,_pos=CommFunc.ReadBYTE(_lpData,_pos)
+            self.GoodItemNumList.append(value)
+        self.SuperItemNumCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.SuperItemNumCount):
+            value,_pos=CommFunc.ReadBYTE(_lpData,_pos)
+            self.SuperItemNumList.append(value)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x12
+        self.ActNum = 0
+        self.GoodItemNumCount = 0
+        self.GoodItemNumList = list()
+        self.SuperItemNumCount = 0
+        self.SuperItemNumList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        length += 1 * self.GoodItemNumCount
+        length += 1
+        length += 1 * self.SuperItemNumCount
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ActNum)
+        data = CommFunc.WriteBYTE(data, self.GoodItemNumCount)
+        for i in range(self.GoodItemNumCount):
+            data = CommFunc.WriteBYTE(data, self.GoodItemNumList[i])
+        data = CommFunc.WriteBYTE(data, self.SuperItemNumCount)
+        for i in range(self.SuperItemNumCount):
+            data = CommFunc.WriteBYTE(data, self.SuperItemNumList[i])
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActNum:%d,
+                                GoodItemNumCount:%d,
+                                GoodItemNumList:%s,
+                                SuperItemNumCount:%d,
+                                SuperItemNumList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActNum,
+                                self.GoodItemNumCount,
+                                "...",
+                                self.SuperItemNumCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagCMActTurntableChooseItem=tagCMActTurntableChooseItem()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMActTurntableChooseItem.Head.Cmd,m_NAtagCMActTurntableChooseItem.Head.SubCmd))] = m_NAtagCMActTurntableChooseItem
+
+
+#------------------------------------------------------
+# AA 13 启动转盘 #tagCMActTurntableStart
+
+class  tagCMActTurntableStart(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ActNum", c_ubyte),    # 活动编号
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x13
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xAA
+        self.SubCmd = 0x13
+        self.ActNum = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMActTurntableStart)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 13 启动转盘 //tagCMActTurntableStart:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ActNum:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ActNum
+                                )
+        return DumpString
+
+
+m_NAtagCMActTurntableStart=tagCMActTurntableStart()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMActTurntableStart.Cmd,m_NAtagCMActTurntableStart.SubCmd))] = m_NAtagCMActTurntableStart
+
+
+#------------------------------------------------------
 # AA 07 许愿池活动刷新奖池 #tagCMActWishingRefresh
 
 class  tagCMActWishingRefresh(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index 2a5ea16..8f6fbc3 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -26533,6 +26533,315 @@
 
 
 #------------------------------------------------------
+# AA 52 转盘活动信息 #tagMCActTurntableInfo
+
+class  tagMCActTurntableItem(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("ItemNum", c_ubyte),    #物品编号 1~n;注意转盘已确定物品编号 与 极品终极物品待选择库编号可能相同,但并不代表同一物品
+                  ("ItemLibType", c_ubyte),    #物品库类型;1-常规,2-极品,3-终极
+                  ("ItemID", c_int),    
+                  ("ItemCount", c_ushort),    
+                  ]
+
+    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.ItemNum = 0
+        self.ItemLibType = 0
+        self.ItemID = 0
+        self.ItemCount = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCActTurntableItem)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 52 转盘活动信息 //tagMCActTurntableInfo:
+                                ItemNum:%d,
+                                ItemLibType:%d,
+                                ItemID:%d,
+                                ItemCount:%d
+                                '''\
+                                %(
+                                self.ItemNum,
+                                self.ItemLibType,
+                                self.ItemID,
+                                self.ItemCount
+                                )
+        return DumpString
+
+
+class  tagMCActTurntableInfo(Structure):
+    Head = tagHead()
+    ActNum = 0    #(BYTE ActNum)// 活动编号
+    StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
+    EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
+    IsDayReset = 0    #(BYTE IsDayReset)// 是否每天重置
+    LimitLV = 0    #(WORD LimitLV)// 限制等级
+    CTGPrizeCount = 0    #(BYTE CTGPrizeCount)
+    CTGPrizeList = list()    #(vector<DWORD> CTGPrizeList)// 累计充值额度奖励次数列表 [奖励第1次所需累计充值额度, 第2次, ...]
+    UseGoldPrizeCount = 0    #(BYTE UseGoldPrizeCount)
+    UseGoldPrizeList = list()    #(vector<DWORD> UseGoldPrizeList)// 累计消费仙玉奖励次数列表 [奖励第1次所需累计消费仙玉, 第2次, ...]
+    TurnItemCount = 0    #(BYTE TurnItemCount)
+    TurnItemList = list()    #(vector<tagMCActTurntableItem> TurnItemList)// 转盘已确定的物品列表,包含常规物品+极品物品+终极物品,活动开始时,后端直接随机生成常规物品,已确定的物品不包含极品、终极物品时需要先选择才能使用转盘;
+    GoodItemCount = 0    #(BYTE GoodItemCount)
+    GoodItemList = list()    #(vector<tagMCActTurntableItem> GoodItemList)// 极品物品待选择库,由玩家从库中选择放入转盘的物品;注意此库中的物品编号仅表示在该库中的编号,可能与转盘已确定的物品编号重复,但并不代表同一物品;
+    GoodItemCanChooseCount = 0    #(BYTE GoodItemCanChooseCount)// 极品物品可选择个数
+    SuperItemCount = 0    #(BYTE SuperItemCount)
+    SuperItemList = list()    #(vector<tagMCActTurntableItem> SuperItemList)// 终极物品待选择库,由玩家从库中选择放入转盘的物品;注意此库中的物品编号仅表示在该库中的编号,可能与转盘已确定的物品编号重复,但并不代表同一物品;
+    SuperItemCanChooseCount = 0    #(BYTE SuperItemCanChooseCount)// 终极物品可选择个数
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x52
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.ActNum,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
+        self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10)
+        self.IsDayReset,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.LimitLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.CTGPrizeCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.CTGPrizeCount):
+            value,_pos=CommFunc.ReadDWORD(_lpData,_pos)
+            self.CTGPrizeList.append(value)
+        self.UseGoldPrizeCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.UseGoldPrizeCount):
+            value,_pos=CommFunc.ReadDWORD(_lpData,_pos)
+            self.UseGoldPrizeList.append(value)
+        self.TurnItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.TurnItemCount):
+            temTurnItemList = tagMCActTurntableItem()
+            _pos = temTurnItemList.ReadData(_lpData, _pos)
+            self.TurnItemList.append(temTurnItemList)
+        self.GoodItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.GoodItemCount):
+            temGoodItemList = tagMCActTurntableItem()
+            _pos = temGoodItemList.ReadData(_lpData, _pos)
+            self.GoodItemList.append(temGoodItemList)
+        self.GoodItemCanChooseCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.SuperItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.SuperItemCount):
+            temSuperItemList = tagMCActTurntableItem()
+            _pos = temSuperItemList.ReadData(_lpData, _pos)
+            self.SuperItemList.append(temSuperItemList)
+        self.SuperItemCanChooseCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x52
+        self.ActNum = 0
+        self.StartDate = ""
+        self.EndtDate = ""
+        self.IsDayReset = 0
+        self.LimitLV = 0
+        self.CTGPrizeCount = 0
+        self.CTGPrizeList = list()
+        self.UseGoldPrizeCount = 0
+        self.UseGoldPrizeList = list()
+        self.TurnItemCount = 0
+        self.TurnItemList = list()
+        self.GoodItemCount = 0
+        self.GoodItemList = list()
+        self.GoodItemCanChooseCount = 0
+        self.SuperItemCount = 0
+        self.SuperItemList = list()
+        self.SuperItemCanChooseCount = 0
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 10
+        length += 10
+        length += 1
+        length += 2
+        length += 1
+        length += 4 * self.CTGPrizeCount
+        length += 1
+        length += 4 * self.UseGoldPrizeCount
+        length += 1
+        for i in range(self.TurnItemCount):
+            length += self.TurnItemList[i].GetLength()
+        length += 1
+        for i in range(self.GoodItemCount):
+            length += self.GoodItemList[i].GetLength()
+        length += 1
+        length += 1
+        for i in range(self.SuperItemCount):
+            length += self.SuperItemList[i].GetLength()
+        length += 1
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ActNum)
+        data = CommFunc.WriteString(data, 10, self.StartDate)
+        data = CommFunc.WriteString(data, 10, self.EndtDate)
+        data = CommFunc.WriteBYTE(data, self.IsDayReset)
+        data = CommFunc.WriteWORD(data, self.LimitLV)
+        data = CommFunc.WriteBYTE(data, self.CTGPrizeCount)
+        for i in range(self.CTGPrizeCount):
+            data = CommFunc.WriteDWORD(data, self.CTGPrizeList[i])
+        data = CommFunc.WriteBYTE(data, self.UseGoldPrizeCount)
+        for i in range(self.UseGoldPrizeCount):
+            data = CommFunc.WriteDWORD(data, self.UseGoldPrizeList[i])
+        data = CommFunc.WriteBYTE(data, self.TurnItemCount)
+        for i in range(self.TurnItemCount):
+            data = CommFunc.WriteString(data, self.TurnItemList[i].GetLength(), self.TurnItemList[i].GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.GoodItemCount)
+        for i in range(self.GoodItemCount):
+            data = CommFunc.WriteString(data, self.GoodItemList[i].GetLength(), self.GoodItemList[i].GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.GoodItemCanChooseCount)
+        data = CommFunc.WriteBYTE(data, self.SuperItemCount)
+        for i in range(self.SuperItemCount):
+            data = CommFunc.WriteString(data, self.SuperItemList[i].GetLength(), self.SuperItemList[i].GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.SuperItemCanChooseCount)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActNum:%d,
+                                StartDate:%s,
+                                EndtDate:%s,
+                                IsDayReset:%d,
+                                LimitLV:%d,
+                                CTGPrizeCount:%d,
+                                CTGPrizeList:%s,
+                                UseGoldPrizeCount:%d,
+                                UseGoldPrizeList:%s,
+                                TurnItemCount:%d,
+                                TurnItemList:%s,
+                                GoodItemCount:%d,
+                                GoodItemList:%s,
+                                GoodItemCanChooseCount:%d,
+                                SuperItemCount:%d,
+                                SuperItemList:%s,
+                                SuperItemCanChooseCount:%d
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActNum,
+                                self.StartDate,
+                                self.EndtDate,
+                                self.IsDayReset,
+                                self.LimitLV,
+                                self.CTGPrizeCount,
+                                "...",
+                                self.UseGoldPrizeCount,
+                                "...",
+                                self.TurnItemCount,
+                                "...",
+                                self.GoodItemCount,
+                                "...",
+                                self.GoodItemCanChooseCount,
+                                self.SuperItemCount,
+                                "...",
+                                self.SuperItemCanChooseCount
+                                )
+        return DumpString
+
+
+m_NAtagMCActTurntableInfo=tagMCActTurntableInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActTurntableInfo.Head.Cmd,m_NAtagMCActTurntableInfo.Head.SubCmd))] = m_NAtagMCActTurntableInfo
+
+
+#------------------------------------------------------
+# AA 53 转盘活动玩家信息 #tagMCActTurntablePlayerInfo
+
+class  tagMCActTurntablePlayerInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ActNum", c_ubyte),    #活动编号
+                  ("CanUseCount", c_ubyte),    #可转盘次数
+                  ("CTGTotal", c_int),    #累计充值额度
+                  ("UseGoldTotal", c_int),    #累计消费仙玉额度
+                  ("TurnItemState", c_int),    #转盘物品已抽中记录,按转盘物品编号二进制位代表是否已抽中
+                  ("GetItemNum", c_ubyte),    #本次抽中的物品编号,非转盘结果时为0,大于0时为通知本次转到的物品编号
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x53
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xAA
+        self.SubCmd = 0x53
+        self.ActNum = 0
+        self.CanUseCount = 0
+        self.CTGTotal = 0
+        self.UseGoldTotal = 0
+        self.TurnItemState = 0
+        self.GetItemNum = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCActTurntablePlayerInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 53 转盘活动玩家信息 //tagMCActTurntablePlayerInfo:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ActNum:%d,
+                                CanUseCount:%d,
+                                CTGTotal:%d,
+                                UseGoldTotal:%d,
+                                TurnItemState:%d,
+                                GetItemNum:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ActNum,
+                                self.CanUseCount,
+                                self.CTGTotal,
+                                self.UseGoldTotal,
+                                self.TurnItemState,
+                                self.GetItemNum
+                                )
+        return DumpString
+
+
+m_NAtagMCActTurntablePlayerInfo=tagMCActTurntablePlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActTurntablePlayerInfo.Cmd,m_NAtagMCActTurntablePlayerInfo.SubCmd))] = m_NAtagMCActTurntablePlayerInfo
+
+
+#------------------------------------------------------
 # AA 1B 许愿池拖动结果 #tagMCActWishingDragResult
 
 class  tagMCPlayerWishingDragInfo(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index 4c30592..c75e21f 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1324,6 +1324,23 @@
                         ("char", "NotifyKey", 0),
                         ),
 
+                "ActTurntable":(
+                        ("DWORD", "CfgID", 1),
+                        ("char", "StartDate", 0),
+                        ("char", "EndDate", 0),
+                        ("WORD", "LVLimit", 0),
+                        ("BYTE", "IsDayReset", 0),
+                        ("BYTE", "CTGTypeEffValue", 0),
+                        ("list", "CTGPrizeList", 0),
+                        ("list", "UseGoldPrizeList", 0),
+                        ("list", "LibChooseCountList", 0),
+                        ("list", "SuperItemLimitRule", 0),
+                        ("dict", "CommItemLib", 0),
+                        ("dict", "GoodItemLib", 0),
+                        ("dict", "SuperItemLib", 0),
+                        ("char", "WorldNotifyKey", 0),
+                        ),
+
                 "ActSingleRecharge":(
                         ("DWORD", "CfgID", 1),
                         ("char", "StartDate", 0),
@@ -4503,6 +4520,41 @@
     def GetAwardItemInfo(self): return self.AwardItemInfo # 奖励物品信息  {世界等级范围:[[物品ID,个数,是否拍品], ...]}
     def GetNotifyKey(self): return self.NotifyKey # 广播
 
+# 转盘活动表
+class IPY_ActTurntable():
+    
+    def __init__(self):
+        self.CfgID = 0
+        self.StartDate = ""
+        self.EndDate = ""
+        self.LVLimit = 0
+        self.IsDayReset = 0
+        self.CTGTypeEffValue = 0
+        self.CTGPrizeList = []
+        self.UseGoldPrizeList = []
+        self.LibChooseCountList = []
+        self.SuperItemLimitRule = []
+        self.CommItemLib = {}
+        self.GoodItemLib = {}
+        self.SuperItemLib = {}
+        self.WorldNotifyKey = ""
+        return
+        
+    def GetCfgID(self): return self.CfgID # 配置ID
+    def GetStartDate(self): return self.StartDate # 开启日期
+    def GetEndDate(self): return self.EndDate # 结束日期
+    def GetLVLimit(self): return self.LVLimit # 限制等级
+    def GetIsDayReset(self): return self.IsDayReset # 是否每天重置
+    def GetCTGTypeEffValue(self): return self.CTGTypeEffValue # 充值有效类型值
+    def GetCTGPrizeList(self): return self.CTGPrizeList # 累计充值奖励次数
+    def GetUseGoldPrizeList(self): return self.UseGoldPrizeList # 累计消费X仙玉奖励次数
+    def GetLibChooseCountList(self): return self.LibChooseCountList # 各道具库选择个数
+    def GetSuperItemLimitRule(self): return self.SuperItemLimitRule # 终极库产出万分率|至少X次后可产出
+    def GetCommItemLib(self): return self.CommItemLib # 普通道具库 {(世界等级A,世界等级B):[[可选物品ID, 个数, 是否拍品], ...], ...}
+    def GetGoodItemLib(self): return self.GoodItemLib # 极品道具库 {(世界等级A,世界等级B):[[可选物品ID, 个数, 是否拍品], ...], ...}
+    def GetSuperItemLib(self): return self.SuperItemLib # 超级道具库 {(世界等级A,世界等级B):[[可选物品ID, 个数, 是否拍品], ...], ...}
+    def GetWorldNotifyKey(self): return self.WorldNotifyKey # 好物品全服广播mark,极品及超级道具默认全服广播
+
 # 单笔累充活动表
 class IPY_ActSingleRecharge():
     
@@ -5771,6 +5823,8 @@
         self.ipyActManyDayRechargeLen = len(self.ipyActManyDayRechargeCache)
         self.ipyActManyDayRechargeAwardCache = self.__LoadFileData("ActManyDayRechargeAward", IPY_ActManyDayRechargeAward)
         self.ipyActManyDayRechargeAwardLen = len(self.ipyActManyDayRechargeAwardCache)
+        self.ipyActTurntableCache = self.__LoadFileData("ActTurntable", IPY_ActTurntable)
+        self.ipyActTurntableLen = len(self.ipyActTurntableCache)
         self.ipyActSingleRechargeCache = self.__LoadFileData("ActSingleRecharge", IPY_ActSingleRecharge)
         self.ipyActSingleRechargeLen = len(self.ipyActSingleRechargeCache)
         self.ipyActSingleRechargeAwardCache = self.__LoadFileData("ActSingleRechargeAward", IPY_ActSingleRechargeAward)
@@ -6303,6 +6357,8 @@
     def GetActManyDayRechargeByIndex(self, index): return self.ipyActManyDayRechargeCache[index]
     def GetActManyDayRechargeAwardCount(self): return self.ipyActManyDayRechargeAwardLen
     def GetActManyDayRechargeAwardByIndex(self, index): return self.ipyActManyDayRechargeAwardCache[index]
+    def GetActTurntableCount(self): return self.ipyActTurntableLen
+    def GetActTurntableByIndex(self, index): return self.ipyActTurntableCache[index]
     def GetActSingleRechargeCount(self): return self.ipyActSingleRechargeLen
     def GetActSingleRechargeByIndex(self, index): return self.ipyActSingleRechargeCache[index]
     def GetActSingleRechargeAwardCount(self): return self.ipyActSingleRechargeAwardLen
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
index ddd35f9..13aee7c 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
@@ -77,7 +77,7 @@
 #  @param packindex 背包索引
 #  @return None
 #  @remarks 函数详细说明.
-def CheckPackHasSpace(curPlayer, packindex):
+def CheckPackHasSpace(curPlayer, packindex=IPY_GameWorld.rptItem, isNotify=False):
     #物品背包是否有剩余空间
     curPack = curPlayer.GetItemManager().GetPack(packindex)
     for i in range(0, curPack.GetCount()):
@@ -86,6 +86,9 @@
         if item.IsEmpty():
             return True
         
+    if isNotify:
+        PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_676165", [packindex])
+        
     return False
 
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActTurntable.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActTurntable.py
new file mode 100644
index 0000000..49a3cc3
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActTurntable.py
@@ -0,0 +1,541 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerActTurntable
+#
+# @todo:转盘活动
+# @author hxp
+# @date 2021-05-06
+# @version 1.0
+#
+# 详细描述: 转盘活动
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2021-05-06 16:30"""
+#-------------------------------------------------------------------------------
+
+
+import PyGameData
+import ShareDefine
+import PlayerControl
+import IpyGameDataPY
+import ItemControler
+import ChPyNetSendPack
+import IPY_GameWorld
+import NetPackCommon
+import GameWorld
+import ChConfig
+
+import random
+
+# 物品库类型
+(
+ItemLibType_Comm, # 常规物品
+ItemLibType_Good, # 极品物品
+ItemLibType_Super, # 终极物品
+) = range(1, 3 + 1)
+
+def OnPlayerLogin(curPlayer):
+    
+    for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_Turntable, {}).values():
+        actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
+        isReset = __CheckPlayerTurntableAction(curPlayer, actNum)
+        if not isReset:
+            # 活动中同步活动信息
+            if actInfo.get(ShareDefine.ActKey_State):
+                AddTurntableUseCountByLogin(curPlayer, actNum)
+                Sync_TurntableActionInfo(curPlayer, actNum)
+                Sync_TurntablePlayerInfo(curPlayer, actNum)
+                
+    return
+
+def PlayerOnDay(curPlayer):
+    
+    for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_Turntable, {}).values():
+        actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
+        if not actInfo.get(ShareDefine.ActKey_State):
+            continue
+        
+        # 过天重置
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableLoginState % actNum, 0)
+        AddTurntableUseCountByLogin(curPlayer, actNum)
+        Sync_TurntablePlayerInfo(curPlayer, actNum)
+        
+    return
+    
+def RefreshTurntableActionInfo(actNum):
+    ## 收到GameServer同步的活动信息,刷新活动信息
+    playerManager = GameWorld.GetPlayerManager()
+    for index in xrange(playerManager.GetPlayerCount()):
+        curPlayer = playerManager.GetPlayerByIndex(index)
+        if curPlayer.GetID() == 0:
+            continue
+        __CheckPlayerTurntableAction(curPlayer, actNum)
+    return
+
+def __CheckPlayerTurntableAction(curPlayer, actNum):
+    ## 检查玩家活动数据信息
+    
+    playerID = curPlayer.GetPlayerID()
+    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_Turntable, actNum)
+    actID = actInfo.get(ShareDefine.ActKey_ID, 0)
+    state = actInfo.get(ShareDefine.ActKey_State, 0)
+    
+    playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableID % actNum) # 玩家身上的活动ID
+    
+    # 活动ID 相同的话不处理
+    if actID == playerActID:
+        GameWorld.DebugLog("转盘活动ID不变,不处理!actNum=%s,actID=%s" % (actNum, actID), playerID)
+        return
+        
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID, 0)
+    actWorldLV = actInfo.get(ShareDefine.ActKey_WorldLV, 0)
+    
+    GameWorld.DebugLog("转盘活动重置! cfgID=%s,actNum=%s,actID=%s,playerActID=%s,state=%s" % (cfgID, actNum, actID, playerActID, state), playerID)
+    
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableID % actNum, actID)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableWorldLV % actNum, actWorldLV)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableLoginState % actNum, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableCTGValue % actNum, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableUseGold % actNum, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableCanUseCount % actNum, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableItemState % actNum, 0)
+    
+    ipyData = None if not cfgID else IpyGameDataPY.GetIpyGameData("ActTurntable", cfgID)
+    if ipyData:
+        numCountList = ipyData.GetLibChooseCountList()
+        numCountTotal = sum([numCount for numCount in numCountList])
+        for num in xrange(1, numCountTotal + 1):
+            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableItemID % (actNum, num), 0)
+            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableItemCount % (actNum, num), 0)
+            
+        if state:
+            # 随机生成常规物品
+            commItemCount = numCountList[0]
+            commItemLib = GameWorld.GetDictValueByRangeKey(ipyData.GetCommItemLib(), actWorldLV, [])
+            random.shuffle(commItemLib) # 打乱下顺序
+            commItemList = commItemLib[:commItemCount]
+            GameWorld.DebugLog("    随机生成常规物品: %s, %s" % (commItemCount, commItemList))
+            for num, itemInfo in enumerate(commItemList, 1):
+                itemID, itemCount, _ = itemInfo
+                PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableItemID % (actNum, num), itemID * 10 + ItemLibType_Comm)
+                PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableItemCount % (actNum, num), itemCount)
+                
+            # 增加登录奖励转盘次数
+            AddTurntableUseCountByLogin(curPlayer, actNum)
+            
+    Sync_TurntableActionInfo(curPlayer, actNum)
+    Sync_TurntablePlayerInfo(curPlayer, actNum)
+    return True
+
+def AddTurntableUseCountByLogin(curPlayer, actNum):
+    ## 登录增加转盘次数
+    if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableLoginState % actNum):
+        return
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableLoginState % actNum, 1)
+    AddTurntableUseCount(curPlayer, actNum, 1)
+    return
+
+def AddTurntableUseCount(curPlayer, actNum, addCount):
+    ## 增加转盘次数
+    canUseCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableCanUseCount % actNum) + addCount
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableCanUseCount % actNum, canUseCount)
+    GameWorld.DebugLog("    增加转盘活动次数: actNum=%s,addCount=%s,canUseCount=%s" % (actNum, addCount, canUseCount))
+    return
+
+def OnPlayerRecharge(curPlayer, curRechargeValue, coinType):
+    ## 玩家充值
+    if curRechargeValue <= 0:
+        return
+    
+    for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_Turntable, {}).values():
+        actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
+        if not actInfo.get(ShareDefine.ActKey_State):
+            GameWorld.DebugLog("转盘当前未开启! actNum=%s" % actNum)
+            continue
+        
+        cfgID = actInfo.get(ShareDefine.ActKey_CfgID, 0)
+        if not cfgID:
+            continue
+        
+        ipyData = IpyGameDataPY.GetIpyGameData("ActTurntable", cfgID)
+        if not ipyData:
+            continue
+        
+        ctgTypeEffValue = ipyData.GetCTGTypeEffValue()
+        if not ctgTypeEffValue & pow(2, coinType):
+            GameWorld.DebugLog("转盘活动充值类型对该活动无效! actNum=%s,coinType=%s,ctgTypeEffValue=%s" 
+                               % (actNum, coinType, ctgTypeEffValue), curPlayer.GetPlayerID())
+            continue
+        
+        ctgPrizeList = ipyData.GetCTGPrizeList()
+        nowCTGValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableCTGValue % actNum)
+        if nowCTGValue >= max(ctgPrizeList):
+            GameWorld.DebugLog("转盘活动充值已达最大记录,actNum=%s,nowCTGValue=%s,maxCTGValue=%s" 
+                               % (actNum, nowCTGValue, max(ctgPrizeList)))
+            continue
+        
+        updCTGValue = nowCTGValue + curRechargeValue
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableCTGValue % actNum, updCTGValue)
+        GameWorld.DebugLog("转盘活动充值,actNum=%s,nowCTGValue=%s,updCTGValue=%s,curRechargeValue=%s" 
+                           % (actNum, nowCTGValue, updCTGValue, curRechargeValue))
+        
+        addTurntableCount = 0
+        for ctgValue in ctgPrizeList:
+            if updCTGValue < ctgValue:
+                break
+            
+            if nowCTGValue < ctgValue and updCTGValue >= ctgValue:
+                addTurntableCount += 1
+                GameWorld.DebugLog("    ctgValue=%s,addTurntableCount=%s" % (ctgValue, addTurntableCount))
+                
+        if addTurntableCount > 0:
+            AddTurntableUseCount(curPlayer, actNum, addTurntableCount)
+        Sync_TurntablePlayerInfo(curPlayer, actNum)
+        
+    return
+
+def OnPlayerUseGold(curPlayer, addUseGold):
+    ## 玩家消耗仙玉
+    
+    if addUseGold <= 0:
+        return
+    
+    for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_Turntable, {}).values():
+        actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
+        if not actInfo.get(ShareDefine.ActKey_State):
+            GameWorld.DebugLog("转盘当前未开启! actNum=%s" % actNum)
+            continue
+        
+        cfgID = actInfo.get(ShareDefine.ActKey_CfgID, 0)
+        if not cfgID:
+            continue
+        
+        ipyData = IpyGameDataPY.GetIpyGameData("ActTurntable", cfgID)
+        if not ipyData:
+            continue
+        
+        useGoldPrizeList = ipyData.GetUseGoldPrizeList()
+        nowUseGold = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableUseGold % actNum)
+        if nowUseGold >= max(useGoldPrizeList):
+            GameWorld.DebugLog("转盘活动消耗仙玉已达最大记录,actNum=%s,nowUseGold=%s,maxUseGoldValue=%s" 
+                               % (actNum, nowUseGold, max(useGoldPrizeList)))
+            continue
+        
+        updUseGold = nowUseGold + addUseGold
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableUseGold % actNum, updUseGold)
+        GameWorld.DebugLog("转盘活动消耗仙玉,actNum=%s,nowUseGold=%s,updUseGold=%s,addUseGold=%s" 
+                           % (actNum, nowUseGold, updUseGold, addUseGold))
+        
+        addTurntableCount = 0
+        for useGold in useGoldPrizeList:
+            if updUseGold < useGold:
+                break
+            
+            if nowUseGold < useGold and updUseGold >= useGold:
+                addTurntableCount += 1
+                GameWorld.DebugLog("    useGold=%s,addTurntableCount=%s" % (useGold, addTurntableCount))
+                
+        if addTurntableCount > 0:
+            AddTurntableUseCount(curPlayer, actNum, addTurntableCount)
+        Sync_TurntablePlayerInfo(curPlayer, actNum)
+        
+    return
+
+#// AA 12 选择转盘活动物品 #tagCMActTurntableChooseItem
+#
+#struct    tagCMActTurntableChooseItem
+#{
+#    tagHead        Head;
+#    BYTE        ActNum;        // 活动编号
+#    BYTE        GoodItemNumCount;
+#    BYTE        GoodItemNumList[GoodItemNumCount];    // 选择的极品物品编号列表
+#    BYTE        SuperItemNumCount;
+#    BYTE        SuperItemNumList[SuperItemNumCount];    // 选择的终极物品编号列表
+#};
+def OnTurntableChooseItem(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    actNum = clientData.ActNum
+    
+    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_Turntable, actNum)
+    if not actInfo.get(ShareDefine.ActKey_State):
+        return
+    
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    if not cfgID:
+        return
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("ActTurntable", cfgID)
+    if not ipyData:
+        return
+    
+    numCountList = ipyData.GetLibChooseCountList()
+    numCountTotal = sum([numCount for numCount in numCountList])
+    if len(numCountList) != 3:
+        return
+    commCount, goodCount, superCount = numCountList
+    
+    canChoose = True
+    for num in xrange(1, numCountTotal + 1):
+        itemIDInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableItemID % (actNum, num))
+        itemID, itemLibType = itemIDInfo / 10, itemIDInfo % 10
+        if itemID and itemLibType != ItemLibType_Comm:
+            canChoose = False
+            GameWorld.DebugLog("    已经选择过了转盘物品了,无法重复选择!")
+            break
+        
+    if not canChoose:
+        return
+    
+    actWorldLV = actInfo.get(ShareDefine.ActKey_WorldLV, 0)
+    goodItemLib = GameWorld.GetDictValueByRangeKey(ipyData.GetGoodItemLib(), actWorldLV, [])
+    chooseGoodItemNumList = clientData.GoodItemNumList
+    if not chooseGoodItemNumList or len(chooseGoodItemNumList) != goodCount or min(chooseGoodItemNumList) <= 0 or max(chooseGoodItemNumList) > len(goodItemLib):
+        GameWorld.ErrLog("    转盘活动极品物品选择错误!actNum=%s,chooseGoodItemNumList=%s,goodCount=%s,goodItemLibLen=%s" 
+                         % (actNum, chooseGoodItemNumList, goodCount, len(goodItemLib)))
+        return
+    
+    superItemLib = GameWorld.GetDictValueByRangeKey(ipyData.GetSuperItemLib(), actWorldLV, [])
+    chooseSuperItemNumList = clientData.SuperItemNumList
+    if not chooseSuperItemNumList or len(chooseSuperItemNumList) != superCount or min(chooseSuperItemNumList) <= 0 or max(chooseSuperItemNumList) > len(superItemLib):
+        GameWorld.ErrLog("    转盘活动终极物品选择错误!actNum=%s,chooseSuperItemNumList=%s,superCount=%s,superItemLibLen=%s" 
+                         % (actNum, chooseSuperItemNumList, superCount, len(superItemLib)))
+        return
+    
+    useNum = commCount # 以普通物品个数为编号,递增
+    GameWorld.DebugLog("转盘活动选择物品: actNum=%s,chooseGoodItemNumList=%s,chooseSuperItemNumList=%s" % (actNum, chooseGoodItemNumList, chooseSuperItemNumList))
+    for chooseGoodNum in chooseGoodItemNumList:
+        useNum += 1
+        itemID, itemCount, _ = goodItemLib[chooseGoodNum - 1]
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableItemID % (actNum, useNum), itemID * 10 + ItemLibType_Good)
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableItemCount % (actNum, useNum), itemCount)
+        GameWorld.DebugLog("    存储选择极品物品: useNum=%s,itemID=%s,itemCount=%s" % (useNum, itemID, itemCount))
+        
+    for chooseSuperNum in chooseSuperItemNumList:
+        useNum += 1
+        itemID, itemCount, _ = superItemLib[chooseSuperNum - 1]
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableItemID % (actNum, useNum), itemID * 10 + ItemLibType_Super)
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableItemCount % (actNum, useNum), itemCount)
+        GameWorld.DebugLog("    存储选择终极物品: useNum=%s,itemID=%s,itemCount=%s" % (useNum, itemID, itemCount))
+        
+    Sync_TurntableActionInfo(curPlayer, actNum)
+    return
+
+#// AA 13 启动转盘 #tagCMActTurntableStart
+#
+#struct    tagCMActTurntableStart
+#{
+#    tagHead        Head;
+#    BYTE        ActNum;        // 活动编号
+#};
+def OnTurntableStart(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    actNum = clientData.ActNum
+    
+    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_Turntable, actNum)
+    if not actInfo.get(ShareDefine.ActKey_State):
+        return
+    
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    if not cfgID:
+        return
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("ActTurntable", cfgID)
+    if not ipyData:
+        return
+    
+    canUseCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableCanUseCount % actNum)
+    if canUseCount <= 0:
+        GameWorld.DebugLog("没有转盘活动次数!actNum=%s" % actNum)
+        return
+    
+    itemState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableItemState % actNum)
+    
+    numCountList = ipyData.GetLibChooseCountList()
+    numCountTotal = sum([numCount for numCount in numCountList])
+    
+    canStart = False
+    hadGetCount = 0
+    isAuctionItem = 0 # 默认非拍品
+    canGetItemInfoDict = {} # 还可以获得的物品信息 {itemLibType:{num:itemInfo, ...}, ...}
+    for num in xrange(1, numCountTotal + 1):
+        itemIDInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableItemID % (actNum, num))
+        itemCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableItemCount % (actNum, num))
+        itemID, itemLibType = itemIDInfo / 10, itemIDInfo % 10
+        if not itemID or not itemCount:
+            continue
+        
+        if itemLibType != ItemLibType_Comm:
+            canStart = True
+            
+        if itemState & pow(2, num):
+            hadGetCount += 1
+            continue
+        
+        if itemLibType not in canGetItemInfoDict:
+            canGetItemInfoDict[itemLibType] = {}
+        canGetItemInfoDict[itemLibType][num] = [itemID, itemCount, isAuctionItem]
+        
+    if not canStart:
+        GameWorld.DebugLog("未选择转盘活动极品终极物品,无法启动转盘!")
+        return
+    
+    if not ItemControler.CheckPackHasSpace(curPlayer, isNotify=True):
+        return
+    
+    superRate, superLimitTurnCount = ipyData.GetSuperItemLimitRule() # 终极库产出万分率|至少X次后可产出
+    
+    GameWorld.DebugLog("启动转盘活动! actNum=%s,itemState=%s,hadGetCount=%s, superLimitTurnCount=%s,superRate=%s" 
+                       % (actNum, itemState, hadGetCount, superLimitTurnCount, superRate))
+    GameWorld.DebugLog("    canGetItemInfoDict=%s" % canGetItemInfoDict)
+    
+    if not canGetItemInfoDict:
+        return
+    
+    randNum = 0
+    worldNotifyKey = ""
+    giveItemInfo = []
+    canGetCommNumList = canGetItemInfoDict.get(ItemLibType_Comm, {}).keys()
+    canGetGoodNumList = canGetItemInfoDict.get(ItemLibType_Good, {}).keys()
+    randNumWithoutSuperList = canGetCommNumList + canGetGoodNumList
+    GameWorld.DebugLog("    不含终极物品的编号: %s" % (randNumWithoutSuperList))
+    
+    if hadGetCount >= superLimitTurnCount and ItemLibType_Super in canGetItemInfoDict:
+        GameWorld.DebugLog("    有机会获得终极物品: superRate=%s" % superRate)
+        if not randNumWithoutSuperList or GameWorld.CanHappen(superRate): # 没有其他物品了必出终极
+            randNum = random.choice(canGetItemInfoDict[ItemLibType_Super].keys())
+            giveItemInfo = canGetItemInfoDict[ItemLibType_Super][randNum]
+            GameWorld.DebugLog("    获得终极物品! randNum=%s,giveItemInfo=%s" % (randNum, giveItemInfo))
+            worldNotifyKey = ipyData.GetWorldNotifyKey()
+        
+    if not giveItemInfo and randNumWithoutSuperList:
+        randNum = random.choice(randNumWithoutSuperList)
+        
+        if randNum in canGetGoodNumList:
+            giveItemInfo = canGetItemInfoDict[ItemLibType_Good][randNum]
+            GameWorld.DebugLog("    获得极品物品! randNum=%s,giveItemInfo=%s" % (randNum, giveItemInfo))
+            worldNotifyKey = ipyData.GetWorldNotifyKey()
+        else:
+            giveItemInfo = canGetItemInfoDict[ItemLibType_Comm][randNum]
+            GameWorld.DebugLog("    获得常规物品! randNum=%s,giveItemInfo=%s" % (randNum, giveItemInfo))
+                
+    if not giveItemInfo or not randNum:
+        return
+    
+    updItemState = itemState | pow(2, randNum)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableItemState % actNum, updItemState)
+    updCanUseCount = canUseCount - 1
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TurntableCanUseCount % actNum, updCanUseCount)
+    GameWorld.DebugLog("    randNum=%s,updItemState=%s,updCanUseCount=%s" % (randNum, updItemState, updCanUseCount))
+    
+    itemID, itemCount, isAuctionItem = giveItemInfo
+    ItemControler.GivePlayerItem(curPlayer, itemID, itemCount, isAuctionItem, [IPY_GameWorld.rptItem], event=["ActTurntable", False, {}])
+    
+    if worldNotifyKey:
+        PlayerControl.WorldNotify(0, worldNotifyKey, [curPlayer.GetPlayerName(), itemID, itemCount])
+        
+    Sync_TurntablePlayerInfo(curPlayer, actNum, randNum)
+    return
+
+
+def Sync_TurntablePlayerInfo(curPlayer, actNum, getItemNum=0):
+    ## 通知玩家数据信息
+    # @param getItemNum: 本次转盘获得的对应物品编号
+    
+    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_Turntable, actNum)
+    if not actInfo.get(ShareDefine.ActKey_State):
+        return
+    
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    if not cfgID:
+        return
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("ActTurntable", cfgID)
+    if not ipyData:
+        return
+    
+    playerActInfo = ChPyNetSendPack.tagMCActTurntablePlayerInfo()
+    playerActInfo.ActNum = actNum
+    playerActInfo.CanUseCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableCanUseCount % actNum)
+    playerActInfo.CTGTotal = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableCTGValue % actNum)
+    playerActInfo.UseGoldTotal = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableUseGold % actNum)
+    playerActInfo.TurnItemState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableItemState % actNum)
+    playerActInfo.GetItemNum = getItemNum
+    NetPackCommon.SendFakePack(curPlayer, playerActInfo)
+    return
+
+def Sync_TurntableActionInfo(curPlayer, actNum):
+    ## 通知活动信息
+    
+    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_Turntable, actNum)
+    if not actInfo.get(ShareDefine.ActKey_State):
+        return
+    
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    if not cfgID:
+        return
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("ActTurntable", cfgID)
+    if not ipyData:
+        return
+    
+    actWorldLV = actInfo.get(ShareDefine.ActKey_WorldLV, 0)
+    openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
+    
+    clientPack = ChPyNetSendPack.tagMCActTurntableInfo()
+    clientPack.ActNum = actNum
+    clientPack.StartDate = GameWorld.GetOperationActionDateStr(ipyData.GetStartDate(), openServerDay)
+    clientPack.EndtDate = GameWorld.GetOperationActionDateStr(ipyData.GetEndDate(), openServerDay)
+    clientPack.IsDayReset = ipyData.GetIsDayReset()
+    clientPack.LimitLV = ipyData.GetLVLimit()
+    clientPack.CTGPrizeList = ipyData.GetCTGPrizeList()
+    clientPack.CTGPrizeCount = len(clientPack.CTGPrizeList)
+    clientPack.UseGoldPrizeList = ipyData.GetUseGoldPrizeList()
+    clientPack.UseGoldPrizeCount = len(clientPack.UseGoldPrizeList)
+    
+    numCountList = ipyData.GetLibChooseCountList()
+    numCountTotal = sum([numCount for numCount in numCountList])
+    
+    clientPack.TurnItemList = []
+    for num in xrange(1, numCountTotal + 1):
+        itemIDInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableItemID % (actNum, num))
+        itemCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TurntableItemCount % (actNum, num))
+        itemID, itemLibType = itemIDInfo / 10, itemIDInfo % 10
+        if not itemID:
+            break
+        packItem = ChPyNetSendPack.tagMCActTurntableItem()
+        packItem.ItemNum = num
+        packItem.ItemLibType = itemLibType
+        packItem.ItemID = itemID
+        packItem.ItemCount = itemCount
+        clientPack.TurnItemList.append(packItem)
+    clientPack.TurnItemCount = len(clientPack.TurnItemList)
+    
+    clientPack.GoodItemCanChooseCount = numCountList[1] if len(numCountList) > 1 else 0
+    goodItemLib = GameWorld.GetDictValueByRangeKey(ipyData.GetGoodItemLib(), actWorldLV, [])
+    for num, itemInfo in enumerate(goodItemLib, 1):
+        itemID, itemCount, _ = itemInfo
+        packItem = ChPyNetSendPack.tagMCActTurntableItem()
+        packItem.ItemNum = num
+        packItem.ItemLibType = ItemLibType_Good
+        packItem.ItemID = itemID
+        packItem.ItemCount = itemCount
+        clientPack.GoodItemList.append(packItem)
+    clientPack.GoodItemCount = len(clientPack.GoodItemList)
+    
+    clientPack.SuperItemCanChooseCount = numCountList[2] if len(numCountList) > 2 else 0
+    superItemLib = GameWorld.GetDictValueByRangeKey(ipyData.GetSuperItemLib(), actWorldLV, [])
+    for num, itemInfo in enumerate(superItemLib, 1):
+        itemID, itemCount, _ = itemInfo
+        packItem = ChPyNetSendPack.tagMCActTurntableItem()
+        packItem.ItemNum = num
+        packItem.ItemLibType = ItemLibType_Super
+        packItem.ItemID = itemID
+        packItem.ItemCount = itemCount
+        clientPack.SuperItemList.append(packItem)
+    clientPack.SuperItemCount = len(clientPack.SuperItemList)
+    
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
index fc7d5e5..9fe81cd 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -71,6 +71,7 @@
 import PyGameData
 import PlayerMagicWeapon
 import PlayerFeastTravel
+import PlayerActTurntable
 import GameLogic_SealDemon
 import GameLogic_ZhuXianBoss
 import GameLogic_CrossDemonKing
@@ -3169,9 +3170,13 @@
     #PlayerGoldAction.PlayerUseGold(curPlayer, price)
     
     # 消费返利
-    PlayerCostRebate.AddCostRebateGold(curPlayer, costType, price, infoDict)
-    PlayerFeastTravel.AddFeastTravelTaskValue(curPlayer, ChConfig.Def_FeastTravel_UseGold, price)
-    
+    if costType not in ChConfig.CostRebate_DisableType:
+        PlayerCostRebate.AddCostRebateGold(curPlayer, costType, price, infoDict)
+        PlayerFeastTravel.AddFeastTravelTaskValue(curPlayer, ChConfig.Def_FeastTravel_UseGold, price)
+        PlayerActTurntable.OnPlayerUseGold(curPlayer, price)
+    else:
+        GameWorld.DebugLog("不计入消费活动的消费类型!costType=%s" % costType, curPlayer.GetPlayerID())
+        
     # 事件汇报
     #===========================================================================
     # if costType == ChConfig.Def_Cost_BourseBuy:
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
index 22eb365..fc07677 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -234,6 +234,7 @@
 OperationActionName_FeastTravel = "ActFeastTravel" # 节日游历活动
 OperationActionName_ManyDayRecharge = "ActManyDayRecharge" # 多日连充活动
 OperationActionName_SingleRecharge = "ActSingleRecharge" # 单笔累充活动
+OperationActionName_Turntable = "ActTurntable" # 转盘活动
 #节日活动类型列表 - 该类型无视开服天,日期到了就开启
 FeastOperationActionNameList = [OperationActionName_FeastWeekParty, OperationActionName_FeastRedPacket,
                                 OperationActionName_RechargeRebateGold, OperationActionName_GrowupBuy,
@@ -251,6 +252,7 @@
                            OperationActionName_NewFairyCeremony, OperationActionName_LuckyTreasure,
                            OperationActionName_DailyGiftbag, OperationActionName_SingleRecharge,
                            OperationActionName_CollectWords, OperationActionName_ManyDayRecharge,
+                           OperationActionName_Turntable,
                            ] + FeastOperationActionNameList
 #需要记录开启活动时的世界等级的运营活动
 NeedWorldLVOperationActNameList = [OperationActionName_FairyCeremony, OperationActionName_WishingWell, 
@@ -259,7 +261,7 @@
                                    OperationActionName_CostRebate, OperationActionName_FlashGiftbag,
                                    OperationActionName_SpringSale, OperationActionName_LuckyTreasure,
                                    OperationActionName_DailyGiftbag, OperationActionName_GrowupBuy,
-                                   OperationActionName_WeekParty,
+                                   OperationActionName_WeekParty, OperationActionName_Turntable,
                                    OperationActionName_CollectWords,
                                    OperationActionName_FeastLogin,
                                    OperationActionName_FeastWish, OperationActionName_FeastTravel,
@@ -271,6 +273,7 @@
                                    OperationActionName_FlashGiftbag, OperationActionName_CostRebate,
                                    OperationActionName_SpringSale, OperationActionName_FlashSale,
                                    OperationActionName_ManyDayRecharge, OperationActionName_SingleRecharge,
+                                   OperationActionName_Turntable,
                                    ]
 
 #跨服运营活动表名定义

--
Gitblit v1.8.0