From e5a52d63b822c0c8624ef45a05a3656fae22d303 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期二, 08 十二月 2020 18:54:10 +0800
Subject: [PATCH] 8605 【港台】【BT】【长尾】【后端】新增限时集字活动

---
 ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py                                     |   82 +++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py           |   19 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py                  |    8 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py                  |   56 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py              |  347 +++++++++++++
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py                                       |   56 ++
 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py                                   |  347 +++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActCollectWords.py |  355 ++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                          |   12 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py                |  114 ++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py              |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py                |    2 
 PySysDB/PySysDBPY.h                                                                                 |   42 +
 ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py                                       |    8 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py    |    7 
 PySysDB/PySysDBG.h                                                                                  |   30 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                     |    4 
 17 files changed, 1,486 insertions(+), 6 deletions(-)

diff --git a/PySysDB/PySysDBG.h b/PySysDB/PySysDBG.h
index c49a5f4..27a8e87 100644
--- a/PySysDB/PySysDBG.h
+++ b/PySysDB/PySysDBG.h
@@ -407,6 +407,36 @@
 	BYTE		IsDayReset;	//是否每天重置
 };
 
+//集字活动时间表
+
+struct tagActCollectWords
+{
+	DWORD		_CfgID;	//配置ID
+	char		ActMark;	//活动组标记
+	list		PlatformList;	//活动平台列表["平台A", "平台A", ...],配[]代表所有
+	list		ServerGroupIDList;	//服务器ID列表
+	char		StartDate;	//开启日期
+	char		EndDate;	//结束日期
+	dict		NotifyInfoStart;	//全服提示信息 - 相对开始时间
+	dict		NotifyInfoEnd;	//全服提示信息 - 相对结束时间
+	list		NotifyInfoLoop;	//全服提示信息 - 循环广播[间隔分钟, 广播key]
+};
+
+//集字活动时间表2
+
+struct tagActCollectWords2
+{
+	DWORD		_CfgID;	//配置ID
+	char		ActMark;	//活动组标记
+	list		PlatformList;	//活动平台列表["平台A", "平台A", ...],配[]代表所有
+	list		ServerGroupIDList;	//服务器ID列表
+	char		StartDate;	//开启日期
+	char		EndDate;	//结束日期
+	dict		NotifyInfoStart;	//全服提示信息 - 相对开始时间
+	dict		NotifyInfoEnd;	//全服提示信息 - 相对结束时间
+	list		NotifyInfoLoop;	//全服提示信息 - 循环广播[间隔分钟, 广播key]
+};
+
 //BOSS复活活动时间表
 
 struct tagActBossReborn
diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index 16f8175..2887a45 100644
--- a/PySysDB/PySysDBPY.h
+++ b/PySysDB/PySysDBPY.h
@@ -1400,6 +1400,48 @@
 	char		NotifyKey;		//全服广播key,默认两个参数(玩家名, 档位额度)
 };
 
+//集字活动时间表
+
+struct tagActCollectWords
+{
+	DWORD		_CfgID;	//配置ID
+	char		StartDate;	//开启日期
+	char		EndDate;	//结束日期
+	WORD		LVLimit;	//限制等级
+	BYTE		LastDayOnlyExchange;	//最后一天是否仅兑换
+	WORD		TemplateID;	//兑换模板编号
+	WORD		DropDiffLVLimit;	//掉落等级差值限制
+	list		DropItemRateList;	//小怪掉落饼图概率
+	list		DropItemRateListBoss;	//Boss掉落饼图概率
+};
+
+//集字活动时间表2
+
+struct tagActCollectWords2
+{
+	DWORD		_CfgID;	//配置ID
+	char		StartDate;	//开启日期
+	char		EndDate;	//结束日期
+	WORD		LVLimit;	//限制等级
+	BYTE		LastDayOnlyExchange;	//最后一天是否仅兑换
+	WORD		TemplateID;	//兑换模板编号
+	WORD		DropDiffLVLimit;	//掉落等级差值限制
+	list		DropItemRateList;	//小怪掉落饼图概率
+	list		DropItemRateListBoss;	//Boss掉落饼图概率
+};
+
+//集字活动兑换模板表
+
+struct tagCollectWordsExchange
+{
+	DWORD		_TemplateID;	//模板ID
+	BYTE		ExchangeNum;	//兑换编号(同个模板中需唯一不可变)
+	list		ExchangeItemInfo;	//兑换目标物品[物品ID,个数,是否绑定]
+	BYTE		ExchangeCountMax;		//最大兑换次数(0不限制)
+	list		NeedItemList;	//所需物品信息列表 [[物品ID,个数,是否绑定], ...]
+	BYTE		NeedNotify;		//是否需要广播
+};
+
 //BOSS复活活动时间表
 
 struct tagActBossReborn
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
index c76019e..70ce0aa 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetPack.py
@@ -13146,6 +13146,62 @@
 
 
 #------------------------------------------------------
+# AA 09 集字活动兑换 #tagCMActCollectWordsExchange
+
+class  tagCMActCollectWordsExchange(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ActNum", c_ubyte),    #活动编号,1 或 2,相互独立的活动,可同时开启
+                  ("ExchangeNum", c_ubyte),    #兑换编号
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x09
+        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 = 0x09
+        self.ActNum = 0
+        self.ExchangeNum = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMActCollectWordsExchange)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 09 集字活动兑换 //tagCMActCollectWordsExchange:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ActNum:%d,
+                                ExchangeNum:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ActNum,
+                                self.ExchangeNum
+                                )
+        return DumpString
+
+
+m_NAtagCMActCollectWordsExchange=tagCMActCollectWordsExchange()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMActCollectWordsExchange.Cmd,m_NAtagCMActCollectWordsExchange.SubCmd))] = m_NAtagCMActCollectWordsExchange
+
+
+#------------------------------------------------------
 # AA 07 许愿池活动刷新奖池 #tagCMActWishingRefresh
 
 class  tagCMActWishingRefresh(Structure):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
index fdee8be..cdcc800 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py
@@ -23884,6 +23884,353 @@
 
 
 #------------------------------------------------------
+# AA 40 集字活动信息 #tagMCActCollectWordsInfo
+
+class  tagMCActCollectWordsNeedItem(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("ItemID", c_int),    
+                  ("ItemCount", c_ushort),    
+                  ("IsBind", c_ubyte),    
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.ItemID = 0
+        self.ItemCount = 0
+        self.IsBind = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCActCollectWordsNeedItem)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 40 集字活动信息 //tagMCActCollectWordsInfo:
+                                ItemID:%d,
+                                ItemCount:%d,
+                                IsBind:%d
+                                '''\
+                                %(
+                                self.ItemID,
+                                self.ItemCount,
+                                self.IsBind
+                                )
+        return DumpString
+
+
+class  tagMCActCollectWordsExchangeItem(Structure):
+    ExchangeNum = 0    #(BYTE ExchangeNum)//兑换编号
+    ExchangeCountMax = 0    #(BYTE ExchangeCountMax)//最大兑换次数,0不限制
+    ItemID = 0    #(DWORD ItemID)//目标物品
+    ItemCount = 0    #(WORD ItemCount)
+    IsBind = 0    #(BYTE IsBind)
+    NeedItemCount = 0    #(BYTE NeedItemCount)
+    NeedItemList = list()    #(vector<tagMCActCollectWordsNeedItem> NeedItemList)// 所需物品列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.ExchangeNum,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ExchangeCountMax,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ItemID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.ItemCount,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.IsBind,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.NeedItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.NeedItemCount):
+            temNeedItemList = tagMCActCollectWordsNeedItem()
+            _pos = temNeedItemList.ReadData(_lpData, _pos)
+            self.NeedItemList.append(temNeedItemList)
+        return _pos
+
+    def Clear(self):
+        self.ExchangeNum = 0
+        self.ExchangeCountMax = 0
+        self.ItemID = 0
+        self.ItemCount = 0
+        self.IsBind = 0
+        self.NeedItemCount = 0
+        self.NeedItemList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        length += 4
+        length += 2
+        length += 1
+        length += 1
+        for i in range(self.NeedItemCount):
+            length += self.NeedItemList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.ExchangeNum)
+        data = CommFunc.WriteBYTE(data, self.ExchangeCountMax)
+        data = CommFunc.WriteDWORD(data, self.ItemID)
+        data = CommFunc.WriteWORD(data, self.ItemCount)
+        data = CommFunc.WriteBYTE(data, self.IsBind)
+        data = CommFunc.WriteBYTE(data, self.NeedItemCount)
+        for i in range(self.NeedItemCount):
+            data = CommFunc.WriteString(data, self.NeedItemList[i].GetLength(), self.NeedItemList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                ExchangeNum:%d,
+                                ExchangeCountMax:%d,
+                                ItemID:%d,
+                                ItemCount:%d,
+                                IsBind:%d,
+                                NeedItemCount:%d,
+                                NeedItemList:%s
+                                '''\
+                                %(
+                                self.ExchangeNum,
+                                self.ExchangeCountMax,
+                                self.ItemID,
+                                self.ItemCount,
+                                self.IsBind,
+                                self.NeedItemCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagMCActCollectWordsInfo(Structure):
+    Head = tagHead()
+    ActNum = 0    #(BYTE ActNum)//活动编号,1 或 2,相互独立的活动,可同时开启
+    StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
+    EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
+    LimitLV = 0    #(WORD LimitLV)// 限制等级
+    LastDayOnlyExchange = 0    #(BYTE LastDayOnlyExchange)//最后一天是否仅兑换
+    ExchangeCount = 0    #(BYTE ExchangeCount)
+    ExchangeItemList = list()    #(vector<tagMCActCollectWordsExchangeItem> ExchangeItemList)//兑换组合列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x40
+        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.LimitLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.LastDayOnlyExchange,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ExchangeCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.ExchangeCount):
+            temExchangeItemList = tagMCActCollectWordsExchangeItem()
+            _pos = temExchangeItemList.ReadData(_lpData, _pos)
+            self.ExchangeItemList.append(temExchangeItemList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x40
+        self.ActNum = 0
+        self.StartDate = ""
+        self.EndtDate = ""
+        self.LimitLV = 0
+        self.LastDayOnlyExchange = 0
+        self.ExchangeCount = 0
+        self.ExchangeItemList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 10
+        length += 10
+        length += 2
+        length += 1
+        length += 1
+        for i in range(self.ExchangeCount):
+            length += self.ExchangeItemList[i].GetLength()
+
+        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.WriteWORD(data, self.LimitLV)
+        data = CommFunc.WriteBYTE(data, self.LastDayOnlyExchange)
+        data = CommFunc.WriteBYTE(data, self.ExchangeCount)
+        for i in range(self.ExchangeCount):
+            data = CommFunc.WriteString(data, self.ExchangeItemList[i].GetLength(), self.ExchangeItemList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActNum:%d,
+                                StartDate:%s,
+                                EndtDate:%s,
+                                LimitLV:%d,
+                                LastDayOnlyExchange:%d,
+                                ExchangeCount:%d,
+                                ExchangeItemList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActNum,
+                                self.StartDate,
+                                self.EndtDate,
+                                self.LimitLV,
+                                self.LastDayOnlyExchange,
+                                self.ExchangeCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagMCActCollectWordsInfo=tagMCActCollectWordsInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActCollectWordsInfo.Head.Cmd,m_NAtagMCActCollectWordsInfo.Head.SubCmd))] = m_NAtagMCActCollectWordsInfo
+
+
+#------------------------------------------------------
+# AA 41 集字活动玩家信息 #tagMCActCollectWordsPlayerInfo
+
+class  tagMCActCollectWordsExchangeInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("ExchangeNum", c_ubyte),    #兑换编号
+                  ("ExchangeCount", 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.ExchangeNum = 0
+        self.ExchangeCount = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCActCollectWordsExchangeInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 41 集字活动玩家信息 //tagMCActCollectWordsPlayerInfo:
+                                ExchangeNum:%d,
+                                ExchangeCount:%d
+                                '''\
+                                %(
+                                self.ExchangeNum,
+                                self.ExchangeCount
+                                )
+        return DumpString
+
+
+class  tagMCActCollectWordsPlayerInfo(Structure):
+    Head = tagHead()
+    ActNum = 0    #(BYTE ActNum)//活动编号,1 或 2,相互独立的活动,可同时开启
+    ExchangeCount = 0    #(BYTE ExchangeCount)
+    ExchangeInfoList = list()    #(vector<tagMCActCollectWordsExchangeInfo> ExchangeInfoList)//兑换数据列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x41
+        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.ExchangeCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.ExchangeCount):
+            temExchangeInfoList = tagMCActCollectWordsExchangeInfo()
+            _pos = temExchangeInfoList.ReadData(_lpData, _pos)
+            self.ExchangeInfoList.append(temExchangeInfoList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x41
+        self.ActNum = 0
+        self.ExchangeCount = 0
+        self.ExchangeInfoList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        for i in range(self.ExchangeCount):
+            length += self.ExchangeInfoList[i].GetLength()
+
+        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.ExchangeCount)
+        for i in range(self.ExchangeCount):
+            data = CommFunc.WriteString(data, self.ExchangeInfoList[i].GetLength(), self.ExchangeInfoList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActNum:%d,
+                                ExchangeCount:%d,
+                                ExchangeInfoList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActNum,
+                                self.ExchangeCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagMCActCollectWordsPlayerInfo=tagMCActCollectWordsPlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActCollectWordsPlayerInfo.Head.Cmd,m_NAtagMCActCollectWordsPlayerInfo.Head.SubCmd))] = m_NAtagMCActCollectWordsPlayerInfo
+
+
+#------------------------------------------------------
 # AA 0C 登录奖励活动信息 #tagMCActLoginAwardInfo
 
 class  tagMCActLoginAwardAction(Structure):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
index 0878b73..ddae138 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
@@ -347,6 +347,30 @@
                         ("BYTE", "IsDayReset", 0),
                         ),
 
+                "ActCollectWords":(
+                        ("DWORD", "CfgID", 1),
+                        ("char", "ActMark", 0),
+                        ("list", "PlatformList", 0),
+                        ("list", "ServerGroupIDList", 0),
+                        ("char", "StartDate", 0),
+                        ("char", "EndDate", 0),
+                        ("dict", "NotifyInfoStart", 0),
+                        ("dict", "NotifyInfoEnd", 0),
+                        ("list", "NotifyInfoLoop", 0),
+                        ),
+
+                "ActCollectWords2":(
+                        ("DWORD", "CfgID", 1),
+                        ("char", "ActMark", 0),
+                        ("list", "PlatformList", 0),
+                        ("list", "ServerGroupIDList", 0),
+                        ("char", "StartDate", 0),
+                        ("char", "EndDate", 0),
+                        ("dict", "NotifyInfoStart", 0),
+                        ("dict", "NotifyInfoEnd", 0),
+                        ("list", "NotifyInfoLoop", 0),
+                        ),
+
                 "ActBossReborn":(
                         ("DWORD", "CfgID", 1),
                         ("list", "ServerGroupIDList", 0),
@@ -1265,6 +1289,56 @@
     def GetNotifyInfoLoop(self): return self.NotifyInfoLoop # 全服提示信息 - 循环广播[间隔分钟, 广播key]
     def GetIsDayReset(self): return self.IsDayReset # 是否每天重置
 
+# 集字活动时间表
+class IPY_ActCollectWords():
+    
+    def __init__(self):
+        self.CfgID = 0
+        self.ActMark = ""
+        self.PlatformList = []
+        self.ServerGroupIDList = []
+        self.StartDate = ""
+        self.EndDate = ""
+        self.NotifyInfoStart = {}
+        self.NotifyInfoEnd = {}
+        self.NotifyInfoLoop = []
+        return
+        
+    def GetCfgID(self): return self.CfgID # 配置ID
+    def GetActMark(self): return self.ActMark # 活动组标记
+    def GetPlatformList(self): return self.PlatformList # 活动平台列表["平台A", "平台A", ...],配[]代表所有
+    def GetServerGroupIDList(self): return self.ServerGroupIDList # 服务器ID列表
+    def GetStartDate(self): return self.StartDate # 开启日期
+    def GetEndDate(self): return self.EndDate # 结束日期
+    def GetNotifyInfoStart(self): return self.NotifyInfoStart # 全服提示信息 - 相对开始时间
+    def GetNotifyInfoEnd(self): return self.NotifyInfoEnd # 全服提示信息 - 相对结束时间
+    def GetNotifyInfoLoop(self): return self.NotifyInfoLoop # 全服提示信息 - 循环广播[间隔分钟, 广播key]
+
+# 集字活动时间表2
+class IPY_ActCollectWords2():
+    
+    def __init__(self):
+        self.CfgID = 0
+        self.ActMark = ""
+        self.PlatformList = []
+        self.ServerGroupIDList = []
+        self.StartDate = ""
+        self.EndDate = ""
+        self.NotifyInfoStart = {}
+        self.NotifyInfoEnd = {}
+        self.NotifyInfoLoop = []
+        return
+        
+    def GetCfgID(self): return self.CfgID # 配置ID
+    def GetActMark(self): return self.ActMark # 活动组标记
+    def GetPlatformList(self): return self.PlatformList # 活动平台列表["平台A", "平台A", ...],配[]代表所有
+    def GetServerGroupIDList(self): return self.ServerGroupIDList # 服务器ID列表
+    def GetStartDate(self): return self.StartDate # 开启日期
+    def GetEndDate(self): return self.EndDate # 结束日期
+    def GetNotifyInfoStart(self): return self.NotifyInfoStart # 全服提示信息 - 相对开始时间
+    def GetNotifyInfoEnd(self): return self.NotifyInfoEnd # 全服提示信息 - 相对结束时间
+    def GetNotifyInfoLoop(self): return self.NotifyInfoLoop # 全服提示信息 - 循环广播[间隔分钟, 广播key]
+
 # BOSS复活活动时间表
 class IPY_ActBossReborn():
     
@@ -1885,6 +1959,10 @@
         self.ipyActExpRateLen = len(self.ipyActExpRateCache)
         self.ipyActCostRebateCache = self.__LoadFileData("ActCostRebate", IPY_ActCostRebate)
         self.ipyActCostRebateLen = len(self.ipyActCostRebateCache)
+        self.ipyActCollectWordsCache = self.__LoadFileData("ActCollectWords", IPY_ActCollectWords)
+        self.ipyActCollectWordsLen = len(self.ipyActCollectWordsCache)
+        self.ipyActCollectWords2Cache = self.__LoadFileData("ActCollectWords2", IPY_ActCollectWords2)
+        self.ipyActCollectWords2Len = len(self.ipyActCollectWords2Cache)
         self.ipyActBossRebornCache = self.__LoadFileData("ActBossReborn", IPY_ActBossReborn)
         self.ipyActBossRebornLen = len(self.ipyActBossRebornCache)
         self.ipyActFairyCeremonyCache = self.__LoadFileData("ActFairyCeremony", IPY_ActFairyCeremony)
@@ -2161,6 +2239,10 @@
     def GetActExpRateByIndex(self, index): return self.ipyActExpRateCache[index]
     def GetActCostRebateCount(self): return self.ipyActCostRebateLen
     def GetActCostRebateByIndex(self, index): return self.ipyActCostRebateCache[index]
+    def GetActCollectWordsCount(self): return self.ipyActCollectWordsLen
+    def GetActCollectWordsByIndex(self, index): return self.ipyActCollectWordsCache[index]
+    def GetActCollectWords2Count(self): return self.ipyActCollectWords2Len
+    def GetActCollectWords2ByIndex(self, index): return self.ipyActCollectWords2Cache[index]
     def GetActBossRebornCount(self): return self.ipyActBossRebornLen
     def GetActBossRebornByIndex(self, index): return self.ipyActBossRebornCache[index]
     def GetActFairyCeremonyCount(self): return self.ipyActFairyCeremonyLen
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
index b4b8dfa..2b442f1 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -216,11 +216,12 @@
 OperationActionName_LoginAward = "ActLoginAward" # 登录奖励活动
 OperationActionName_FeastWeekParty = "ActFeastWeekParty" # 节日巡礼狂欢活动
 OperationActionName_FeastRedPacket = "ActFeastRedPacket" # 节日红包活动
-OperationActionName_FeastCollectWords = "ActFeastCollectWords" # 节日集字活动
+OperationActionName_CollectWords = "ActCollectWords" # 集字活动
+OperationActionName_CollectWords2 = "ActCollectWords2" # 集字活动2
 OperationActionName_LuckyTreasure = "ActLuckyTreasure" # 幸运鉴宝活动
 OperationActionName_RechargePrize = "ActRechargePrize" # 充值返利活动
 #节日活动类型列表 - 该类型无视开服天,日期到了就开启
-FeastOperationActionNameList = [OperationActionName_FeastWeekParty, OperationActionName_FeastRedPacket, OperationActionName_FeastCollectWords]
+FeastOperationActionNameList = [OperationActionName_FeastWeekParty, OperationActionName_FeastRedPacket]
 #所有的运营活动列表,含节日活动
 OperationActionNameList = [OperationActionName_ExpRate, OperationActionName_CostRebate, 
                            OperationActionName_BossReborn,OperationActionName_SpringSale, 
@@ -229,7 +230,8 @@
                            OperationActionName_WishingWell, OperationActionName_TotalRecharge, 
                            OperationActionName_WeekParty, OperationActionName_LoginAward, 
                            OperationActionName_NewFairyCeremony, OperationActionName_LuckyTreasure,
-                           OperationActionName_DailyGiftbag, OperationActionName_RechargePrize] \
+                           OperationActionName_DailyGiftbag, OperationActionName_RechargePrize, 
+                           OperationActionName_CollectWords, OperationActionName_CollectWords2] \
                            + FeastOperationActionNameList
 #需要记录开启活动时的世界等级的运营活动
 NeedWorldLVOperationActNameList = [OperationActionName_FairyCeremony, OperationActionName_WishingWell, 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index d29ef5c..fdd6096 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1370,6 +1370,18 @@
 PacketSubCMD_2=0x06
 PacketCallFunc_2=OnActWishingDrag
 
+;集字活动
+[PlayerActCollectWords]
+ScriptName = Player\PlayerActCollectWords.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 1
+
+PacketCMD_1=0xAA
+PacketSubCMD_1=0x09
+PacketCallFunc_1=OnActCollectWordsExchange
+
 ;聚魂
 [PlayerGatherSoul]
 ScriptName = Player\PlayerGatherSoul.py
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index 9e49cce..575fbd4 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -3718,6 +3718,10 @@
 Def_PDict_DailyGiftbagID = "DailyGiftbagID"  # 玩家身上的每日礼包活动ID,唯一标识,取活动开始日期time
 Def_PDict_DailyGiftbagBuyCount = "DailyGiftbagBuyCount_%s"  # 每日礼包已购买次数,参数(礼包ID)
 
+#集字活动
+Def_PDict_CollectWordsID = "CollectWordsID_%s"  # 玩家身上的活动ID,唯一标识,取活动开始日期time值,参数(活动编号 1 或  2)
+Def_PDict_CollectWordsExchangeCount = "CollectWordsCount_%s_%s"  # 兑换编号对应已兑换次数,参数(活动编号, 兑换编号)
+
 #BOSS复活
 Def_PDict_BossRebornID = "BossRebornID"  # 玩家身上的BOSS复活活动ID,唯一标识,取活动开始日期time值
 Def_PDict_BossRebornTemplateID = "BossRebornTemplateID"  # 玩家身上的BOSS复活模板ID
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index c76019e..70ce0aa 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -13146,6 +13146,62 @@
 
 
 #------------------------------------------------------
+# AA 09 集字活动兑换 #tagCMActCollectWordsExchange
+
+class  tagCMActCollectWordsExchange(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ActNum", c_ubyte),    #活动编号,1 或 2,相互独立的活动,可同时开启
+                  ("ExchangeNum", c_ubyte),    #兑换编号
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x09
+        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 = 0x09
+        self.ActNum = 0
+        self.ExchangeNum = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCMActCollectWordsExchange)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 09 集字活动兑换 //tagCMActCollectWordsExchange:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ActNum:%d,
+                                ExchangeNum:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ActNum,
+                                self.ExchangeNum
+                                )
+        return DumpString
+
+
+m_NAtagCMActCollectWordsExchange=tagCMActCollectWordsExchange()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCMActCollectWordsExchange.Cmd,m_NAtagCMActCollectWordsExchange.SubCmd))] = m_NAtagCMActCollectWordsExchange
+
+
+#------------------------------------------------------
 # 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 fdee8be..cdcc800 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -23884,6 +23884,353 @@
 
 
 #------------------------------------------------------
+# AA 40 集字活动信息 #tagMCActCollectWordsInfo
+
+class  tagMCActCollectWordsNeedItem(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("ItemID", c_int),    
+                  ("ItemCount", c_ushort),    
+                  ("IsBind", c_ubyte),    
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.ItemID = 0
+        self.ItemCount = 0
+        self.IsBind = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCActCollectWordsNeedItem)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 40 集字活动信息 //tagMCActCollectWordsInfo:
+                                ItemID:%d,
+                                ItemCount:%d,
+                                IsBind:%d
+                                '''\
+                                %(
+                                self.ItemID,
+                                self.ItemCount,
+                                self.IsBind
+                                )
+        return DumpString
+
+
+class  tagMCActCollectWordsExchangeItem(Structure):
+    ExchangeNum = 0    #(BYTE ExchangeNum)//兑换编号
+    ExchangeCountMax = 0    #(BYTE ExchangeCountMax)//最大兑换次数,0不限制
+    ItemID = 0    #(DWORD ItemID)//目标物品
+    ItemCount = 0    #(WORD ItemCount)
+    IsBind = 0    #(BYTE IsBind)
+    NeedItemCount = 0    #(BYTE NeedItemCount)
+    NeedItemList = list()    #(vector<tagMCActCollectWordsNeedItem> NeedItemList)// 所需物品列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.ExchangeNum,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ExchangeCountMax,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ItemID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.ItemCount,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.IsBind,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.NeedItemCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.NeedItemCount):
+            temNeedItemList = tagMCActCollectWordsNeedItem()
+            _pos = temNeedItemList.ReadData(_lpData, _pos)
+            self.NeedItemList.append(temNeedItemList)
+        return _pos
+
+    def Clear(self):
+        self.ExchangeNum = 0
+        self.ExchangeCountMax = 0
+        self.ItemID = 0
+        self.ItemCount = 0
+        self.IsBind = 0
+        self.NeedItemCount = 0
+        self.NeedItemList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 1
+        length += 4
+        length += 2
+        length += 1
+        length += 1
+        for i in range(self.NeedItemCount):
+            length += self.NeedItemList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.ExchangeNum)
+        data = CommFunc.WriteBYTE(data, self.ExchangeCountMax)
+        data = CommFunc.WriteDWORD(data, self.ItemID)
+        data = CommFunc.WriteWORD(data, self.ItemCount)
+        data = CommFunc.WriteBYTE(data, self.IsBind)
+        data = CommFunc.WriteBYTE(data, self.NeedItemCount)
+        for i in range(self.NeedItemCount):
+            data = CommFunc.WriteString(data, self.NeedItemList[i].GetLength(), self.NeedItemList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                ExchangeNum:%d,
+                                ExchangeCountMax:%d,
+                                ItemID:%d,
+                                ItemCount:%d,
+                                IsBind:%d,
+                                NeedItemCount:%d,
+                                NeedItemList:%s
+                                '''\
+                                %(
+                                self.ExchangeNum,
+                                self.ExchangeCountMax,
+                                self.ItemID,
+                                self.ItemCount,
+                                self.IsBind,
+                                self.NeedItemCount,
+                                "..."
+                                )
+        return DumpString
+
+
+class  tagMCActCollectWordsInfo(Structure):
+    Head = tagHead()
+    ActNum = 0    #(BYTE ActNum)//活动编号,1 或 2,相互独立的活动,可同时开启
+    StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
+    EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
+    LimitLV = 0    #(WORD LimitLV)// 限制等级
+    LastDayOnlyExchange = 0    #(BYTE LastDayOnlyExchange)//最后一天是否仅兑换
+    ExchangeCount = 0    #(BYTE ExchangeCount)
+    ExchangeItemList = list()    #(vector<tagMCActCollectWordsExchangeItem> ExchangeItemList)//兑换组合列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x40
+        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.LimitLV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.LastDayOnlyExchange,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.ExchangeCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.ExchangeCount):
+            temExchangeItemList = tagMCActCollectWordsExchangeItem()
+            _pos = temExchangeItemList.ReadData(_lpData, _pos)
+            self.ExchangeItemList.append(temExchangeItemList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x40
+        self.ActNum = 0
+        self.StartDate = ""
+        self.EndtDate = ""
+        self.LimitLV = 0
+        self.LastDayOnlyExchange = 0
+        self.ExchangeCount = 0
+        self.ExchangeItemList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 10
+        length += 10
+        length += 2
+        length += 1
+        length += 1
+        for i in range(self.ExchangeCount):
+            length += self.ExchangeItemList[i].GetLength()
+
+        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.WriteWORD(data, self.LimitLV)
+        data = CommFunc.WriteBYTE(data, self.LastDayOnlyExchange)
+        data = CommFunc.WriteBYTE(data, self.ExchangeCount)
+        for i in range(self.ExchangeCount):
+            data = CommFunc.WriteString(data, self.ExchangeItemList[i].GetLength(), self.ExchangeItemList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActNum:%d,
+                                StartDate:%s,
+                                EndtDate:%s,
+                                LimitLV:%d,
+                                LastDayOnlyExchange:%d,
+                                ExchangeCount:%d,
+                                ExchangeItemList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActNum,
+                                self.StartDate,
+                                self.EndtDate,
+                                self.LimitLV,
+                                self.LastDayOnlyExchange,
+                                self.ExchangeCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagMCActCollectWordsInfo=tagMCActCollectWordsInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActCollectWordsInfo.Head.Cmd,m_NAtagMCActCollectWordsInfo.Head.SubCmd))] = m_NAtagMCActCollectWordsInfo
+
+
+#------------------------------------------------------
+# AA 41 集字活动玩家信息 #tagMCActCollectWordsPlayerInfo
+
+class  tagMCActCollectWordsExchangeInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("ExchangeNum", c_ubyte),    #兑换编号
+                  ("ExchangeCount", 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.ExchangeNum = 0
+        self.ExchangeCount = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagMCActCollectWordsExchangeInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 41 集字活动玩家信息 //tagMCActCollectWordsPlayerInfo:
+                                ExchangeNum:%d,
+                                ExchangeCount:%d
+                                '''\
+                                %(
+                                self.ExchangeNum,
+                                self.ExchangeCount
+                                )
+        return DumpString
+
+
+class  tagMCActCollectWordsPlayerInfo(Structure):
+    Head = tagHead()
+    ActNum = 0    #(BYTE ActNum)//活动编号,1 或 2,相互独立的活动,可同时开启
+    ExchangeCount = 0    #(BYTE ExchangeCount)
+    ExchangeInfoList = list()    #(vector<tagMCActCollectWordsExchangeInfo> ExchangeInfoList)//兑换数据列表
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x41
+        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.ExchangeCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.ExchangeCount):
+            temExchangeInfoList = tagMCActCollectWordsExchangeInfo()
+            _pos = temExchangeInfoList.ReadData(_lpData, _pos)
+            self.ExchangeInfoList.append(temExchangeInfoList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xAA
+        self.Head.SubCmd = 0x41
+        self.ActNum = 0
+        self.ExchangeCount = 0
+        self.ExchangeInfoList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 1
+        length += 1
+        for i in range(self.ExchangeCount):
+            length += self.ExchangeInfoList[i].GetLength()
+
+        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.ExchangeCount)
+        for i in range(self.ExchangeCount):
+            data = CommFunc.WriteString(data, self.ExchangeInfoList[i].GetLength(), self.ExchangeInfoList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                ActNum:%d,
+                                ExchangeCount:%d,
+                                ExchangeInfoList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.ActNum,
+                                self.ExchangeCount,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagMCActCollectWordsPlayerInfo=tagMCActCollectWordsPlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActCollectWordsPlayerInfo.Head.Cmd,m_NAtagMCActCollectWordsPlayerInfo.Head.SubCmd))] = m_NAtagMCActCollectWordsPlayerInfo
+
+
+#------------------------------------------------------
 # AA 0C 登录奖励活动信息 #tagMCActLoginAwardInfo
 
 class  tagMCActLoginAwardAction(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index 960ee3b..5e1b168 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1117,6 +1117,39 @@
                         ("char", "NotifyKey", 0),
                         ),
 
+                "ActCollectWords":(
+                        ("DWORD", "CfgID", 1),
+                        ("char", "StartDate", 0),
+                        ("char", "EndDate", 0),
+                        ("WORD", "LVLimit", 0),
+                        ("BYTE", "LastDayOnlyExchange", 0),
+                        ("WORD", "TemplateID", 0),
+                        ("WORD", "DropDiffLVLimit", 0),
+                        ("list", "DropItemRateList", 0),
+                        ("list", "DropItemRateListBoss", 0),
+                        ),
+
+                "ActCollectWords2":(
+                        ("DWORD", "CfgID", 1),
+                        ("char", "StartDate", 0),
+                        ("char", "EndDate", 0),
+                        ("WORD", "LVLimit", 0),
+                        ("BYTE", "LastDayOnlyExchange", 0),
+                        ("WORD", "TemplateID", 0),
+                        ("WORD", "DropDiffLVLimit", 0),
+                        ("list", "DropItemRateList", 0),
+                        ("list", "DropItemRateListBoss", 0),
+                        ),
+
+                "CollectWordsExchange":(
+                        ("DWORD", "TemplateID", 1),
+                        ("BYTE", "ExchangeNum", 0),
+                        ("list", "ExchangeItemInfo", 0),
+                        ("BYTE", "ExchangeCountMax", 0),
+                        ("list", "NeedItemList", 0),
+                        ("BYTE", "NeedNotify", 0),
+                        ),
+
                 "ActBossReborn":(
                         ("DWORD", "CfgID", 1),
                         ("char", "StartDate", 0),
@@ -3891,6 +3924,75 @@
     def GetAwardItemList(self): return self.AwardItemList # 返利物品信息列表 {世界等级范围:[({职业:物品ID,..},个数,是否绑定), ...]}
     def GetNotifyKey(self): return self.NotifyKey # 全服广播key,默认两个参数(玩家名, 档位额度)
 
+# 集字活动时间表
+class IPY_ActCollectWords():
+    
+    def __init__(self):
+        self.CfgID = 0
+        self.StartDate = ""
+        self.EndDate = ""
+        self.LVLimit = 0
+        self.LastDayOnlyExchange = 0
+        self.TemplateID = 0
+        self.DropDiffLVLimit = 0
+        self.DropItemRateList = []
+        self.DropItemRateListBoss = []
+        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 GetLastDayOnlyExchange(self): return self.LastDayOnlyExchange # 最后一天是否仅兑换
+    def GetTemplateID(self): return self.TemplateID # 兑换模板编号
+    def GetDropDiffLVLimit(self): return self.DropDiffLVLimit # 掉落等级差值限制
+    def GetDropItemRateList(self): return self.DropItemRateList # 小怪掉落饼图概率
+    def GetDropItemRateListBoss(self): return self.DropItemRateListBoss # Boss掉落饼图概率
+
+# 集字活动时间表2
+class IPY_ActCollectWords2():
+    
+    def __init__(self):
+        self.CfgID = 0
+        self.StartDate = ""
+        self.EndDate = ""
+        self.LVLimit = 0
+        self.LastDayOnlyExchange = 0
+        self.TemplateID = 0
+        self.DropDiffLVLimit = 0
+        self.DropItemRateList = []
+        self.DropItemRateListBoss = []
+        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 GetLastDayOnlyExchange(self): return self.LastDayOnlyExchange # 最后一天是否仅兑换
+    def GetTemplateID(self): return self.TemplateID # 兑换模板编号
+    def GetDropDiffLVLimit(self): return self.DropDiffLVLimit # 掉落等级差值限制
+    def GetDropItemRateList(self): return self.DropItemRateList # 小怪掉落饼图概率
+    def GetDropItemRateListBoss(self): return self.DropItemRateListBoss # Boss掉落饼图概率
+
+# 集字活动兑换模板表
+class IPY_CollectWordsExchange():
+    
+    def __init__(self):
+        self.TemplateID = 0
+        self.ExchangeNum = 0
+        self.ExchangeItemInfo = []
+        self.ExchangeCountMax = 0
+        self.NeedItemList = []
+        self.NeedNotify = 0
+        return
+        
+    def GetTemplateID(self): return self.TemplateID # 模板ID
+    def GetExchangeNum(self): return self.ExchangeNum # 兑换编号(同个模板中需唯一不可变)
+    def GetExchangeItemInfo(self): return self.ExchangeItemInfo # 兑换目标物品[物品ID,个数,是否绑定]
+    def GetExchangeCountMax(self): return self.ExchangeCountMax # 最大兑换次数(0不限制)
+    def GetNeedItemList(self): return self.NeedItemList # 所需物品信息列表 [[物品ID,个数,是否绑定], ...]
+    def GetNeedNotify(self): return self.NeedNotify # 是否需要广播
+
 # BOSS复活活动时间表
 class IPY_ActBossReborn():
     
@@ -5181,6 +5283,12 @@
         self.ipyActCostRebateLen = len(self.ipyActCostRebateCache)
         self.ipyCostRebateTemplateCache = self.__LoadFileData("CostRebateTemplate", IPY_CostRebateTemplate)
         self.ipyCostRebateTemplateLen = len(self.ipyCostRebateTemplateCache)
+        self.ipyActCollectWordsCache = self.__LoadFileData("ActCollectWords", IPY_ActCollectWords)
+        self.ipyActCollectWordsLen = len(self.ipyActCollectWordsCache)
+        self.ipyActCollectWords2Cache = self.__LoadFileData("ActCollectWords2", IPY_ActCollectWords2)
+        self.ipyActCollectWords2Len = len(self.ipyActCollectWords2Cache)
+        self.ipyCollectWordsExchangeCache = self.__LoadFileData("CollectWordsExchange", IPY_CollectWordsExchange)
+        self.ipyCollectWordsExchangeLen = len(self.ipyCollectWordsExchangeCache)
         self.ipyActBossRebornCache = self.__LoadFileData("ActBossReborn", IPY_ActBossReborn)
         self.ipyActBossRebornLen = len(self.ipyActBossRebornCache)
         self.ipyBossRebornCache = self.__LoadFileData("BossReborn", IPY_BossReborn)
@@ -5673,6 +5781,12 @@
     def GetActCostRebateByIndex(self, index): return self.ipyActCostRebateCache[index]
     def GetCostRebateTemplateCount(self): return self.ipyCostRebateTemplateLen
     def GetCostRebateTemplateByIndex(self, index): return self.ipyCostRebateTemplateCache[index]
+    def GetActCollectWordsCount(self): return self.ipyActCollectWordsLen
+    def GetActCollectWordsByIndex(self, index): return self.ipyActCollectWordsCache[index]
+    def GetActCollectWords2Count(self): return self.ipyActCollectWords2Len
+    def GetActCollectWords2ByIndex(self, index): return self.ipyActCollectWords2Cache[index]
+    def GetCollectWordsExchangeCount(self): return self.ipyCollectWordsExchangeLen
+    def GetCollectWordsExchangeByIndex(self, index): return self.ipyCollectWordsExchangeCache[index]
     def GetActBossRebornCount(self): return self.ipyActBossRebornLen
     def GetActBossRebornByIndex(self, index): return self.ipyActBossRebornCache[index]
     def GetBossRebornCount(self): return self.ipyBossRebornLen
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 1a224f2..6647255 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
@@ -2636,6 +2636,25 @@
     ClearPack(curPlayer, ShareDefine.rptTempItem)
     return
 
+def CheckPackSpaceEnough(curPlayer, itemList, isNotify=True):
+    ## 检查玩家对应背包是否足够放入物品
+    needPackSpaceDict = {}
+    for itemID, itemCnt, isAuctionItem in itemList:
+        curItem = GameWorld.GetGameData().GetItemByTypeID(itemID)
+        if not curItem:
+            return False
+        packType = ChConfig.GetItemPackType(curItem.GetType())
+        needSpace = GetItemNeedPackCount(packType, curItem, itemCnt, isAuctionItem)
+        needPackSpaceDict[packType] = needPackSpaceDict.get(packType, 0) + needSpace
+        
+    for packType, needSpace in needPackSpaceDict.items():
+        if needSpace > ItemCommon.GetItemPackSpace(curPlayer, packType, needSpace):
+            if isNotify:
+                PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_676165", [packType])
+            return False
+        
+    return True
+
 def GivePlayerItemOrMail(curPlayer, itemList, mailKey=None, event=["", False, {}]):
     ##给物品,背包满则发邮件
     if not itemList:
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
index 023265f..4a407f6 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
@@ -50,6 +50,7 @@
 import FormulaControl
 import PlayerBossReborn
 import PlayerFairyCeremony
+import PlayerActCollectWords
 import PlayerNewFairyCeremony
 import GameLogic_CrossGrassland
 import PlayerWeekParty
@@ -4217,6 +4218,7 @@
         if not dropPlayer:
             return
         curNPC = self.__Instance
+        PlayerActCollectWords.OnKillNPCDrop(dropPlayer, curNPC)
         if curNPC.GetType() in [ChConfig.ntPriWoodPilePVE, ChConfig.ntPriWoodPilePVP]:
             GameWorld.DebugLog("木桩怪,不掉落物品!")
             return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
index 2f6b764..0ae2231 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -99,6 +99,7 @@
 import PlayerFlashGiftbag
 import PlayerDailyGiftbag
 import PlayerCostRebate
+import PlayerActCollectWords
 import PlayerActTotalRecharge
 import PlayerActRechargePrize
 import PlayerSpringSale
@@ -649,6 +650,8 @@
     PlayerDailyGiftbag.OnPlayerLogin(curPlayer)
     #限时抢购
     PlayerFlashSale.OnPlayerLogin(curPlayer)
+    #集字活动
+    PlayerActCollectWords.OnPlayerLogin(curPlayer)
     # 世界boss
     BossHurtMng.OnLogin(curPlayer)
     ChItem.Sync_ItemDayUseCnt(curPlayer)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActCollectWords.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActCollectWords.py
new file mode 100644
index 0000000..7f0cbfa
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActCollectWords.py
@@ -0,0 +1,355 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerActCollectWords
+#
+# @todo:集字活动
+# @author hxp
+# @date 2020-12-08
+# @version 1.0
+#
+# 详细描述: 集字活动
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2020-12-08 19:00"""
+#-------------------------------------------------------------------------------
+import GameWorld
+import PyGameData
+import ShareDefine
+import PlayerControl
+import ChConfig
+import IpyGameDataPY
+import ChPyNetSendPack
+import NetPackCommon
+import ItemCommon
+import ItemControler
+import IPY_GameWorld
+
+ActCollectWordsNameDict = {
+                           1:ShareDefine.OperationActionName_CollectWords,
+                           2:ShareDefine.OperationActionName_CollectWords2,
+                           }
+
+def OnPlayerLogin(curPlayer):
+    ## 玩家登录
+    
+    for actNum, actName in ActCollectWordsNameDict.items():
+        
+        isReset = __CheckPlayerCollectWordsAction(curPlayer, actNum)
+        if not isReset:
+            actInfo = PyGameData.g_operationActionDict.get(actName, {})
+            # 活动中同步活动信息
+            if actInfo.get(ShareDefine.ActKey_State):
+                SyncCollectWordsActionInfo(curPlayer, actNum)
+                SyncCollectWordsPlayerInfo(curPlayer, actNum)
+                
+    return
+
+def RefreshActCollectWordsInfo(actNum):
+    ## 收到GameServer同步的活动信息,刷新活动信息
+    playerManager = GameWorld.GetPlayerManager()
+    for index in xrange(playerManager.GetPlayerCount()):
+        curPlayer = playerManager.GetPlayerByIndex(index)
+        if curPlayer.GetID() == 0:
+            continue
+        __CheckPlayerCollectWordsAction(curPlayer, actNum)
+        
+    return
+
+def __CheckPlayerCollectWordsAction(curPlayer, actNum):
+    ## 检查玩活动数据信息
+    
+    if actNum not in ActCollectWordsNameDict:
+        return
+    actName = ActCollectWordsNameDict[actNum]
+    
+    playerID = curPlayer.GetPlayerID()
+    actInfo = PyGameData.g_operationActionDict.get(actName, {})
+    actID = actInfo.get(ShareDefine.ActKey_ID, 0)
+    state = actInfo.get(ShareDefine.ActKey_State, 0)
+    
+    playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CollectWordsID % actNum) # 玩家身上的活动ID
+    
+    # 活动ID 相同的话不处理
+    if actID == playerActID:
+        GameWorld.DebugLog("集字活动ID不变,不处理!actNum=%s,actID=%s" % (actNum, actID), curPlayer.GetPlayerID())
+        return
+    
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID, 0)
+    actIpyData = IpyGameDataPY.GetIpyGameData(actName, cfgID)
+    templateID = 0 if not actIpyData else actIpyData.GetTemplateID()
+    exchangeList = IpyGameDataPY.GetIpyGameDataList("CollectWordsExchange", templateID)
+    if not exchangeList:
+        GameWorld.ErrLog("集字兑换找不到兑换模板配置!actNum=%s,cfgID=%s,templateID=%s" % (actNum, cfgID, templateID), playerID)
+        return
+    
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CollectWordsID % actNum, actID)
+    for exchangeIpyData in exchangeList:
+        exchangeNum = exchangeIpyData.GetExchangeNum()
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CollectWordsExchangeCount % (actNum, exchangeNum), 0)
+        
+    GameWorld.DebugLog("集字活动重置! actNum=%s,cfgID=%s,templateID=%s,actID=%s" % (actNum, cfgID, templateID, actID), playerID)
+    
+    if state:
+        SyncCollectWordsActionInfo(curPlayer, actNum)
+        SyncCollectWordsPlayerInfo(curPlayer, actNum)
+        
+    return True
+
+def OnKillNPCDrop(curPlayer, curNPC):
+    ## 击杀NPC掉字逻辑
+    
+    if curNPC.GetType() in [ChConfig.ntPriWoodPilePVP]:
+        return
+    
+    for actNum, actName in ActCollectWordsNameDict.items():
+        
+        actInfo = PyGameData.g_operationActionDict.get(actName, {})
+        if not actInfo:
+            continue
+        
+        if not actInfo.get(ShareDefine.ActKey_State):
+            continue
+        
+        cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+        ipyData = IpyGameDataPY.GetIpyGameData(actName, cfgID)
+        if not ipyData:
+            continue
+        
+        isBoss = ChConfig.IsGameBoss(curNPC)
+        playerLV = curPlayer.GetLV()
+        npcLV = curNPC.GetLV()
+        limitLV = ipyData.GetLVLimit()
+        if not isBoss and limitLV and limitLV > playerLV:
+            #GameWorld.DebugLog("集字活动玩家等级不足,无法掉落! actNum=%s,cfgID=%s,limitLV=%s" % (actNum, cfgID, limitLV))
+            continue
+        
+        dropDiffLVLimit = ipyData.GetDropDiffLVLimit()
+        if not isBoss and dropDiffLVLimit and (playerLV - npcLV) > dropDiffLVLimit:
+            #GameWorld.DebugLog("集字活动玩家等级与NPC等级差值过大,无法掉落! actNum=%s,cfgID=%s,playerLV(%s) - npcLV(%s) > %s" 
+            #                   % (actNum, cfgID, playerLV, npcLV, dropDiffLVLimit))
+            continue
+        
+        lastDayOnlyExchange = ipyData.GetLastDayOnlyExchange()
+        if lastDayOnlyExchange:
+            openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
+            endDateStr = GameWorld.GetOperationActionDateStr(ipyData.GetEndDate(), openServerDay)
+            curDate = GameWorld.GetCurrentTime()
+            curDateStr = "%d-%s-%s" % (curDate.year, curDate.month, curDate.day)
+            if curDateStr == endDateStr:
+                #GameWorld.DebugLog("集字活动最后一天不掉落! %s" % curDateStr)
+                continue
+            
+        randList = ipyData.GetDropItemRateListBoss() if isBoss else ipyData.GetDropItemRateList()
+        dropItemID = GameWorld.GetResultByRandomList(randList)
+        if not dropItemID:
+            continue
+        GameWorld.DebugLog("集字活动掉落物品! actNum=%,npcID=%s,dropItemID=%s" % (actNum, curNPC.GetNPCID(), dropItemID))
+        
+        itemCount = 1 # 默认1个
+        isAuctionItem = 0 # 非拍品
+        ItemControler.GivePlayerItem(curPlayer, dropItemID, itemCount, isAuctionItem, [IPY_GameWorld.rptItem])
+        
+    return
+
+#// AA 09 集字活动兑换 #tagCMActCollectWordsExchange
+#
+#struct    tagCMActCollectWordsExchange
+#{
+#    tagHead        Head;
+#    BYTE        ActNum;    //活动编号,1 或 2,相互独立的活动,可同时开启
+#    BYTE        ExchangeNum;    //兑换编号
+#};
+def OnActCollectWordsExchange(index, clientData, tick):
+    actNum = clientData.ActNum
+    exchangeNum = clientData.ExchangeNum
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    
+    GameWorld.DebugLog("集字活动兑换!actNum=%s,exchangeNum=%s" % (actNum, exchangeNum))
+    
+    if actNum not in ActCollectWordsNameDict:
+        return
+    actName = ActCollectWordsNameDict[actNum]
+    
+    actInfo = PyGameData.g_operationActionDict.get(actName, {})
+    if not actInfo:
+        return
+    
+    if not actInfo.get(ShareDefine.ActKey_State):
+        GameWorld.DebugLog("非集字活动中,无法兑换!actNum=%s" % actNum)
+        return
+    
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    ipyData = IpyGameDataPY.GetIpyGameData(actName, cfgID)
+    if not ipyData:
+        return
+    
+    templateID = ipyData.GetTemplateID()
+    if not templateID:
+        return
+    
+    exchangeList = IpyGameDataPY.GetIpyGameDataList("CollectWordsExchange", templateID)
+    if not exchangeList:
+        return
+    
+    findIpyData = None
+    for exchangeIpyData in exchangeList:
+        if exchangeNum == exchangeIpyData.GetExchangeNum():
+            findIpyData = exchangeIpyData
+            break
+        
+    if not findIpyData:
+        GameWorld.ErrLog("找不到集字活动兑换配置数据!actNum=%s,cfgID=%s,templateID=%s,exchangeNum=%s" 
+                         % (actNum, cfgID, templateID, exchangeNum))
+        return
+    
+    exchangeCountMax = findIpyData.GetExchangeCountMax()
+    curExchangeCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CollectWordsExchangeCount % (actNum, exchangeNum))
+    if exchangeCountMax and curExchangeCount >= exchangeCountMax:
+        GameWorld.DebugLog("超过最大集字兑换次数!templateID=%s,exchangeNum=%s,curExchangeCount=%s > %s" 
+                           % (templateID, exchangeNum, curExchangeCount, exchangeCountMax))
+        return
+    
+    exchangeItemInfo = findIpyData.GetExchangeItemInfo()
+    if len(exchangeItemInfo) != 3:
+        return
+    exchangeItemID = exchangeItemInfo[0]
+    exchangeCount = exchangeItemInfo[1]
+    exchangeIsBind = exchangeItemInfo[2]
+    
+    if not ItemControler.CheckPackSpaceEnough(curPlayer, [[exchangeItemID, exchangeCount, exchangeIsBind]]):
+        return
+    
+    delItemList = []
+    needItemList = findIpyData.GetNeedItemList()
+    for needItemID, needCount, _ in needItemList:
+        costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, needItemID, needCount)
+        if bindCnt + unBindCnt < needCount:
+            GameWorld.DebugLog("集字兑换所需物品不足!exchangeItemID=%s,needItemID=%s,needCount=%s > %s" 
+                               % (exchangeItemID, needItemID, needCount, bindCnt + unBindCnt))
+            return
+        delItemList.append([costItemIndexList, bindCnt, unBindCnt, needCount])
+        
+    if exchangeCountMax:
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CollectWordsExchangeCount % (actNum, exchangeNum), curExchangeCount + 1)
+        SyncCollectWordsPlayerInfo(curPlayer, actNum, exchangeNum)
+        
+    eventName = "CollectWordsExchange"
+    for costItemIndexList, bindCnt, unBindCnt, needCount in delItemList:
+        ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, needCount, eventName)
+        
+    ItemControler.GivePlayerItem(curPlayer, exchangeItemID, exchangeCount, exchangeIsBind, [IPY_GameWorld.rptItem], event=[eventName, False, {}])
+    
+    if findIpyData.GetNeedNotify():
+        PlayerControl.WorldNotify(0, "CollectWordsExchange", [curPlayer.GetPlayerName(), exchangeItemID])
+        
+    return
+
+def SyncCollectWordsActionInfo(curPlayer, actNum):
+    ## 同步活动信息
+    
+    if actNum not in ActCollectWordsNameDict:
+        return
+    actName = ActCollectWordsNameDict[actNum]
+    
+    actInfo = PyGameData.g_operationActionDict.get(actName, {})
+    if not actInfo:
+        return
+    
+    if not actInfo.get(ShareDefine.ActKey_State):
+        return
+    
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    ipyData = IpyGameDataPY.GetIpyGameData(actName, cfgID)
+    if not ipyData:
+        return
+    
+    templateID = ipyData.GetTemplateID()
+    if not templateID:
+        return
+    
+    openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
+    actInfo = ChPyNetSendPack.tagMCActCollectWordsInfo()
+    actInfo.ActNum = actNum
+    actInfo.StartDate = GameWorld.GetOperationActionDateStr(ipyData.GetStartDate(), openServerDay)
+    actInfo.EndtDate = GameWorld.GetOperationActionDateStr(ipyData.GetEndDate(), openServerDay)
+    actInfo.LimitLV = ipyData.GetLVLimit()
+    actInfo.LastDayOnlyExchange = ipyData.GetLastDayOnlyExchange()
+    actInfo.ExchangeItemList = []
+    
+    exchangeList = IpyGameDataPY.GetIpyGameDataList("CollectWordsExchange", templateID)
+    if exchangeList:
+        for exchangeIpyData in exchangeList:
+            itemID, itemCount, isBind = exchangeIpyData.GetExchangeItemInfo()
+            needItemList = exchangeIpyData.GetNeedItemList()
+            
+            exchangeItem = ChPyNetSendPack.tagMCActCollectWordsExchangeItem()
+            exchangeItem.ExchangeNum = exchangeIpyData.GetExchangeNum()
+            exchangeItem.ExchangeCountMax = exchangeIpyData.GetExchangeCountMax()
+            exchangeItem.ItemID = itemID
+            exchangeItem.ItemCount = itemCount
+            exchangeItem.IsBind = isBind
+            exchangeItem.NeedItemList = []
+            for needItemID, needCount, needIsBind in needItemList:
+                needItem = ChPyNetSendPack.tagMCActCollectWordsNeedItem()
+                needItem.ItemID = needItemID
+                needItem.ItemCount = needCount
+                needItem.IsBind = needIsBind
+                exchangeItem.NeedItemList.append(needItem)
+            exchangeItem.NeedItemCount = len(exchangeItem.NeedItemList)
+            
+            actInfo.ExchangeItemList.append(exchangeItem)
+            
+    actInfo.ExchangeCount = len(actInfo.ExchangeItemList)
+    NetPackCommon.SendFakePack(curPlayer, actInfo)
+    return
+
+def SyncCollectWordsPlayerInfo(curPlayer, actNum, exchangeNum=0):
+    ## 同步活动玩家数据
+    
+    if actNum not in ActCollectWordsNameDict:
+        return
+    actName = ActCollectWordsNameDict[actNum]
+    
+    actInfo = PyGameData.g_operationActionDict.get(actName, {})
+    if not actInfo:
+        return
+    
+    if not actInfo.get(ShareDefine.ActKey_State):
+        return
+    
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    ipyData = IpyGameDataPY.GetIpyGameData(actName, cfgID)
+    if not ipyData:
+        return
+    
+    templateID = ipyData.GetTemplateID()
+    if not templateID:
+        return
+    
+    exchangeList = IpyGameDataPY.GetIpyGameDataList("CollectWordsExchange", templateID)
+    if not exchangeList:
+        return
+    
+    clientPack = ChPyNetSendPack.tagMCActCollectWordsPlayerInfo()
+    clientPack.ActNum = actNum
+    clientPack.ExchangeInfoList = []
+    for exchangeIpyData in exchangeList:
+        ipyExchangeNum = exchangeIpyData.GetExchangeNum()
+        if exchangeNum and exchangeNum != ipyExchangeNum:
+            continue
+        
+        exchangeInfo = ChPyNetSendPack.tagMCActCollectWordsExchangeInfo()
+        exchangeInfo.ExchangeNum = ipyExchangeNum
+        exchangeInfo.ExchangeCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CollectWordsExchangeCount % (actNum, ipyExchangeNum)) 
+        clientPack.ExchangeInfoList.append(exchangeInfo)
+        
+        if exchangeNum:
+            break
+        
+    clientPack.ExchangeCount = len(clientPack.ExchangeInfoList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
index 00a3214..f9a821b 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -74,6 +74,7 @@
 import GameLogic_FamilyWar
 import OpenServerCampaign
 import PlayerCostRebate
+import PlayerActCollectWords
 import PlayerActTotalRecharge
 import PlayerActRechargePrize
 import PlayerSpringSale
@@ -1365,6 +1366,12 @@
             elif actionName == ShareDefine.OperationActionName_WishingWell:
                 PlayerWishingWell.RefreshWishingWellAction()
                 
+            elif actionName == ShareDefine.OperationActionName_CollectWords:
+                PlayerActCollectWords.RefreshActCollectWordsInfo(1)
+                
+            elif actionName == ShareDefine.OperationActionName_CollectWords2:
+                PlayerActCollectWords.RefreshActCollectWordsInfo(2)
+                
             elif actionName == ShareDefine.OperationActionName_WeekParty:
                 PlayerWeekParty.RefreshOperationAction_WeekParty()
                 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
index b4b8dfa..2b442f1 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -216,11 +216,12 @@
 OperationActionName_LoginAward = "ActLoginAward" # 登录奖励活动
 OperationActionName_FeastWeekParty = "ActFeastWeekParty" # 节日巡礼狂欢活动
 OperationActionName_FeastRedPacket = "ActFeastRedPacket" # 节日红包活动
-OperationActionName_FeastCollectWords = "ActFeastCollectWords" # 节日集字活动
+OperationActionName_CollectWords = "ActCollectWords" # 集字活动
+OperationActionName_CollectWords2 = "ActCollectWords2" # 集字活动2
 OperationActionName_LuckyTreasure = "ActLuckyTreasure" # 幸运鉴宝活动
 OperationActionName_RechargePrize = "ActRechargePrize" # 充值返利活动
 #节日活动类型列表 - 该类型无视开服天,日期到了就开启
-FeastOperationActionNameList = [OperationActionName_FeastWeekParty, OperationActionName_FeastRedPacket, OperationActionName_FeastCollectWords]
+FeastOperationActionNameList = [OperationActionName_FeastWeekParty, OperationActionName_FeastRedPacket]
 #所有的运营活动列表,含节日活动
 OperationActionNameList = [OperationActionName_ExpRate, OperationActionName_CostRebate, 
                            OperationActionName_BossReborn,OperationActionName_SpringSale, 
@@ -229,7 +230,8 @@
                            OperationActionName_WishingWell, OperationActionName_TotalRecharge, 
                            OperationActionName_WeekParty, OperationActionName_LoginAward, 
                            OperationActionName_NewFairyCeremony, OperationActionName_LuckyTreasure,
-                           OperationActionName_DailyGiftbag, OperationActionName_RechargePrize] \
+                           OperationActionName_DailyGiftbag, OperationActionName_RechargePrize, 
+                           OperationActionName_CollectWords, OperationActionName_CollectWords2] \
                            + FeastOperationActionNameList
 #需要记录开启活动时的世界等级的运营活动
 NeedWorldLVOperationActNameList = [OperationActionName_FairyCeremony, OperationActionName_WishingWell, 

--
Gitblit v1.8.0