From 5d79b486b2974522c2d1978dc90c3081827224e0 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期四, 26 二月 2026 15:46:46 +0800
Subject: [PATCH] 493 【活动内容】武将登场-服务端

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py |   28 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py               |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py                      |   36 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py                      |  112 +++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py                  |  311 +++-----
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTreasure.py            |  139 +++-
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetXunbao.py            |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py           |   54 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBBillboard.py        |   10 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActSign.py             |   98 +++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Billboard.py            |   13 
 /dev/null                                                                                               |  278 --------
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerHero.py                |   13 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                              |   16 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActHeroAppear.py       |  379 +++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldAction.py   |   22 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py                    |  224 ++++--
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py                  |   28 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCoin.py                |    2 
 PySysDB/PySysDBPY.h                                                                                     |   79 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameFuncComm.py              |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py        |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                         |   23 
 23 files changed, 1,201 insertions(+), 678 deletions(-)

diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index 1904918..e73cfd8 100644
--- a/PySysDB/PySysDBPY.h
+++ b/PySysDB/PySysDBPY.h
@@ -1225,6 +1225,7 @@
 	list		ItemListEx;	//扩展物品列表[[物品ID,个数,是否绑定],...]
 	BYTE		ResetType;	//重置类型
 	DWORD		LimitCnt;	//个人限制数量
+	DWORD		CostItemID;	//消耗道具ID
 	BYTE		MoneyType;	//金钱类型
 	DWORD		MoneyNum;	//金钱数量
 	DWORD		MoneyOriginal;	//原价
@@ -1435,10 +1436,10 @@
 struct tagTreasureSet
 {
 	BYTE		_TreasureType;	//寻宝类型
-	BYTE		PackType;	//放入背包
-	BYTE		CheckPack;	//是否检查背包
-	BYTE		IsActType;	//是否活动寻宝
+	list		CheckPackList;	//检查背包类型列表
+	BYTE		ActType;	//活动寻宝类型
 	DWORD		DailyMaxCount;	//每日最大次数
+	DWORD		DailyMaxCountMoney;	//每日货币次数
 	BYTE		DailyFreeCount;	//每日免费次数
 	list		TreasureCountList;	//抽奖次数列表
 	char		RecycleItemMail;	//重置回收道具邮件,如果有配置回收邮件key,则重置时会回收多余的寻宝道具
@@ -1451,10 +1452,12 @@
 	char		LuckyRateFormat;	//幸运格子概率公式
 	BYTE		LuckyGridNum;	//幸运格子编号
 	dict		GridNumMaxLimitInfo;	//格子最大产出次数限制,{"格子":最大可产出次数, ...}
+	list		RecordGridNumList;	//需要记录产出的格子
 	list		NotifyGridNumList;	//需要额外广播的格子
 	dict		NotifyKeyDict;	//广播key
 	BYTE		AwardMoneyType;	//额外奖励货币类型
 	WORD		AwardMoneyValue;	//单次奖励货币数
+	list		AwardItemInfo;	//单次额外奖励道具,物品ID|个数
 	BYTE		WishReset;	//心愿重置规则
 	dict		WishLibSelect;	//心愿库选择数
 	dict		WishLibPubFreeCnt;	//心愿库公共免费次数
@@ -1882,31 +1885,59 @@
 	list		AwardItemList;	//任务奖励列表[[物品ID,个数,是否拍品], ...]
 };
 
-//登录活动奖励时间表新
+//活动签到奖励表
 
-struct tagActLoginNew
-{
-	DWORD		_CfgID;	//配置ID
-	char		StartDate;	//开启日期
-	char		EndDate;	//结束日期
-	WORD		RelateFuncID;	//关联功能ID
-	BYTE		FuncActDays;	//功能活动天数
-	BYTE		FuncLoop;	//功能是否循环
-	WORD		LVLimit;	//限制等级
-	list		RepSignCostMoneyInfo;	//补签消耗货币类型数量
-	BYTE		TemplateID;	//登录奖励模板编号
-	WORD		AwardExCTGID;	//扩展奖励礼包充值ID
-	WORD		ActZhanlingType;	//关联活动战令类型
-};
-
-//登录活动奖励模板表新
-
-struct tagActLoginNewAward
+struct ActSignAward
 {
 	BYTE		_TemplateID;	//模板ID
 	BYTE		DayNum;	//第X天从1开始
-	list		LoginAwardItemList;	//奖励列表[[物品ID,个数,是否拍品], ...]
-	list		LoginAwardItemListEx;	//扩展奖励列表[[物品ID,个数,是否拍品], ...]
+	list		SignAwardItemList;	//奖励列表[[物品ID,个数], ...]
+};
+
+//活动排行奖励表
+
+struct ActBillboardAward
+{
+	DWORD		_TemplateID;	//模板ID
+	WORD		RankA;	//名次A
+	WORD		RankB;	//至名次B
+	float		NeedValue;	//至少所需值
+	list		AwardItemList;	//奖励物品列表[[物品ID,个数], ...]
+};
+
+//武将登场时间表
+
+struct ActHeroAppear
+{
+	DWORD		_CfgID;	//配置ID
+	list		PlatformList;	//活动平台列表["平台A", "平台A", ...],配[]代表所有
+	list		ServerIDList;	//服务器ID列表
+	BYTE		ActNum;	//活动分组编号, 活动类型 * 10 + 不同界面编号
+	char		StartDate;	//开启日期
+	char		EndDate;	//结束日期
+	list		ActHeroIDList;	//登场武将ID列表
+	WORD		ActTreasureType;	//招募寻宝类型
+	BYTE		StarGiftTempID;	//专属升星礼包模板
+	list		SkinCTGIDList;	//时装充值ID列表
+	list		GiftCTGIDList;	//礼包充值ID列表
+	WORD		GiftShopType;	//礼包商店类型
+	WORD		ExShopType;	//兑换商店类型
+	char		ExShopRecycleMail;	//兑换货币回收邮件
+	WORD		SignTempID;	//签到奖励模板
+	WORD		BillTempID;	//排行奖励模板
+	char		BillAwardMail;	//榜单奖励发放邮件
+};
+
+//升星计划奖励表
+
+struct ActHeroAppearStar
+{
+	BYTE		_StarTempID;	//模板ID
+	BYTE		NeedStar;	//所需星
+	BYTE		AwardIndex;	//奖励记录索引
+	list		FreeAwardItemList;	//免费奖励物品信息列表[[物品ID,个数], ...]
+	WORD		StarGiftCTGID;	//星级礼包充值ID
+	dict		HeroGiftItemInfo;	//登场武将额外专属奖励信息{"武将ID":[[专属物品ID,个数], ...], ...}
 };
 
 //装备位背包索引映射表
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index 774f6b1..3f9c875 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -658,6 +658,22 @@
 PacketSubCMD_4=0x06
 PacketCallFunc_4=OnQueryRecharge
 
+;武将登场
+[PlayerActHeroAppear]
+ScriptName = Player\PlayerActHeroAppear.py
+Writer = hxp
+Releaser = hxp
+RegType = 0
+RegisterPackCount = 2
+
+PacketCMD_1=0xAA
+PacketSubCMD_1=0x01
+PacketCallFunc_1=OnStarHeroSelect
+
+PacketCMD_2=0xAA
+PacketSubCMD_2=0x02
+PacketCallFunc_2=OnCallHeroSelect
+
 ;炼器活动
 [PlayerActLianqi]
 ScriptName = Player\PlayerActLianqi.py
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index ae89eb9..b85a86e 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -565,6 +565,7 @@
 Def_ItemType_CanUseByCDTime = 145 # 创建后根据CDTime到后可开启
 
 Def_ItemType_Hero = 150 # 武将英雄
+Def_ItemType_HeroPiece = 151 # 武将英雄碎片
 
 Def_ItemType_GY_Taiyang = 201       # 太阳 注意修改装备列表配置 Def_MGGuayuType
 Def_ItemType_GY_Shaoyang = 202      # 少阳
@@ -3274,6 +3275,7 @@
 Def_PDict_TreasureCount = "TreasureCount_%s"  # 寻宝次数, 参数(寻宝类型)
 Def_PDict_TreasureCountEx = "TreasureCountEx_%s"  # 第x次x抽必出,按第x次单抽、10连抽记录, 参数(寻宝类型)
 Def_PDict_TreasureCountToday = "TreasureCountToday_%s"  # 今日寻宝次数, 参数(寻宝类型)
+Def_PDict_TreasureCountTodayGold = "TreasureCountTodayG_%s"  # 今日元宝寻宝次数, 参数(寻宝类型)
 Def_PDict_TreasureLuck = "TreasureLuck_%s"  # 寻宝当前幸运值, 参数(寻宝类型)
 Def_PDict_TreasureCntAward = "TreasureCntAward_%s"  # 累计寻宝次数对应物品奖励领奖状态, 参数(寻宝类型)
 Def_PDict_TreasureGridCnt = "TreasureGridCnt_%s_%s"  # 格子对应累计产出次数, 参数(寻宝类型, 格子编号)
@@ -3517,17 +3519,22 @@
 Def_PDict_ZhanlingRewardFree = "ZhanlingRewardFree_%s_%s"  # 战令免费奖励领取记录,按类型二进制位运算记录是否已领取,参数(类型,key编号)
 Def_PDict_ZhanlingFinishTime = "ZhanlingFinishTime_%s"  # 战令奖励全部领取完毕的时间戳,参数(类型)
 
-#登录活动新
-Def_PDict_ActLoginNewID = "ActLoginNewID_%s"  # 玩家身上的活动ID,唯一标识,取活动开始日期time值,参数:(活动编号)
-Def_PDict_ActLoginNewAward = "ActLoginNewAward_%s"  # 登录活动奖励记录,按位记录登录天是否已领取,参数:(活动编号)
-Def_PDict_ActLoginNewAwardEx = "ActLoginNewAwardEx_%s"  # 登录活动额外奖励记录,按位记录登录天是否已领取,参数:(活动编号)
-
 #任务活动
 Def_PDict_ActTaskID = "ActTaskID_%s"  # 玩家身上的活动ID,唯一标识,取活动开始日期time值,参数:(活动编号)
 Def_PDict_ActTaskTempID = "ActTaskTempID_%s"  # 任务活动模板ID,参数:(活动编号)
 Def_PDict_ActTaskValue = "ActTaskValue_%s_%s"  # 任务活动当前任务进度值,参数:(活动编号, 任务类型)
 Def_PDict_ActTaskAward = "ActTaskAward_%s_%s"  # 任务活动奖励记录,按位记录任务ID是否已领取,参数:(活动编号,key编号)
 Def_PDict_ActTaskRound = "ActTaskRound_%s"  # 任务轮次,参数:(活动编号)
+
+#活动签到
+Def_PDict_ActSignAward = "ActSignAward_%s_%s"  # 活动签到奖励记录,按位记录活动天是否已领取,参数:(活动类型, 活动编号)
+
+#武将登场
+Def_PDict_ActHeroAppearCfgID = "ActHeroAppearCfgID_%s"  # 活动对应的CfgID,参数:(活动编号)
+Def_PDict_ActHeroAppearID = "ActHeroAppearID_%s"  # 玩家身上的活动ID,唯一标识,取活动开始日期time值,参数:(活动编号)
+Def_PDict_ActHeroAppearStarIndex = "ActHeroAppearStarIndex_%s"  # 升星计划武将ID索引,参数:(活动编号)
+Def_PDict_ActHeroAppearStarAward = "ActHeroAppearStarAward_%s"  # 升星计划免费奖励记录,按奖励索引二进制记录是否已领取,参数:(活动编号)
+Def_PDict_ActHeroAppearCallIndex = "ActHeroAppearCallIndex_%s"  # 招募武将ID索引,参数:(活动编号)
 
 #轮回殿活动
 Def_PDict_ActLunhuidianID = "ActLunhuidianID_%s"  # 玩家身上的活动ID,唯一标识,取活动开始日期time值,参数:(活动编号)
@@ -4664,7 +4671,7 @@
 Def_RewardType_7, # 每日任务修行点奖励7
 Def_RewardType_FirstCharge, # 首充礼包奖励8
 Def_RewardType_OSACelebrationPointAward, # 开服庆典积分阶段奖励 9
-Def_RewardType_10, # 极品白拿10
+Def_RewardType_ActHeroAppearStarFreeAward, # 武将登场升星计划免费奖励 10
 Def_RewardType_CostRebate, # 消费返利11
 Def_RewardType_BossReborn, # BOSS复活12
 Def_RewardType_13, # 仙界盛典充值大礼13
@@ -4676,7 +4683,7 @@
 Def_RewardType_IceLodeStar, # 冰晶矿脉星级奖励19
 Def_RewardType_20,
 Def_RewardType_21,
-Def_RewardType_ActLoginAwardAct, # 领取登录奖励活动奖励22
+Def_RewardType_22, # 领取登录奖励活动奖励22
 Def_RewardType_23, # 新仙界盛典充值大礼23
 Def_RewardType_24, # 新仙界盛典全民来嗨24
 Def_RewardType_25,
@@ -4724,7 +4731,7 @@
 Def_RewardType_LikeGame, #游戏点赞 67
 Def_RewardType_RealmLVUpTask, #境界渡劫任务条件奖励 68
 Def_RewardType_MineTreasure, #福地聚宝盆奖励 69
-Def_RewardType_ActLoginAwardNew, # 领取登录活动奖励70
+Def_RewardType_ActSignAward, # 领取活动签到奖励70
 Def_RewardType_ActTask, # 领取任务活动奖励71
 Def_RewardType_ActBuyCountGift, # 领取购买次数礼包活动 72
 Def_RewardType_Guaji, # 领取挂机收益 73
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 8bb63c4..64697d5 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -8138,6 +8138,118 @@
 
 
 #------------------------------------------------------
+# AA 02 武将登场招募武将选择 #tagCSActHeroAppearCallHeroSelect
+
+class  tagCSActHeroAppearCallHeroSelect(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ActNum", c_ubyte),    # 活动编号
+                  ("CallHeroIndex", c_ubyte),    # 招募选择的武将ID索引
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x02
+        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 = 0x02
+        self.ActNum = 0
+        self.CallHeroIndex = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCSActHeroAppearCallHeroSelect)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 02 武将登场招募武将选择 //tagCSActHeroAppearCallHeroSelect:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ActNum:%d,
+                                CallHeroIndex:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ActNum,
+                                self.CallHeroIndex
+                                )
+        return DumpString
+
+
+m_NAtagCSActHeroAppearCallHeroSelect=tagCSActHeroAppearCallHeroSelect()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCSActHeroAppearCallHeroSelect.Cmd,m_NAtagCSActHeroAppearCallHeroSelect.SubCmd))] = m_NAtagCSActHeroAppearCallHeroSelect
+
+
+#------------------------------------------------------
+# AA 01 武将登场升星武将选择 #tagCSActHeroAppearStarHeroSelect
+
+class  tagCSActHeroAppearStarHeroSelect(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ActNum", c_ubyte),    # 活动编号
+                  ("StarHeroIndex", c_ubyte),    # 升星计划选择的武将ID索引
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x01
+        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 = 0x01
+        self.ActNum = 0
+        self.StarHeroIndex = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCSActHeroAppearStarHeroSelect)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 01 武将登场升星武将选择 //tagCSActHeroAppearStarHeroSelect:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ActNum:%d,
+                                StarHeroIndex:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ActNum,
+                                self.StarHeroIndex
+                                )
+        return DumpString
+
+
+m_NAtagCSActHeroAppearStarHeroSelect=tagCSActHeroAppearStarHeroSelect()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCSActHeroAppearStarHeroSelect.Cmd,m_NAtagCSActHeroAppearStarHeroSelect.SubCmd))] = m_NAtagCSActHeroAppearStarHeroSelect
+
+
+#------------------------------------------------------
 # AA 25 炼器操作 #tagCMActLianqiOP
 
 class  tagCMActLianqiOP(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index f22632b..cd9d3ff 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -7467,6 +7467,7 @@
     LuckValue = 0    #(WORD LuckValue)//当前幸运值
     TreasureCount = 0    #(DWORD TreasureCount)//已寻宝总次数
     TreasureCountToday = 0    #(DWORD TreasureCountToday)//今日已寻宝总次数
+    TreasureCountTodayGold = 0    #(DWORD TreasureCountTodayGold)//今日消耗货币已寻宝总次数
     FreeCountToday = 0    #(WORD FreeCountToday)//今日已免费寻宝次数
     TreasureCntAward = 0    #(DWORD TreasureCntAward)//累计寻宝次数对应奖励领奖状态,按奖励记录索引二进制记录是否已领取
     GridLimitCnt = 0    #(BYTE GridLimitCnt)
@@ -7485,6 +7486,7 @@
         self.LuckValue,_pos = CommFunc.ReadWORD(_lpData, _pos)
         self.TreasureCount,_pos = CommFunc.ReadDWORD(_lpData, _pos)
         self.TreasureCountToday,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.TreasureCountTodayGold,_pos = CommFunc.ReadDWORD(_lpData, _pos)
         self.FreeCountToday,_pos = CommFunc.ReadWORD(_lpData, _pos)
         self.TreasureCntAward,_pos = CommFunc.ReadDWORD(_lpData, _pos)
         self.GridLimitCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos)
@@ -7504,6 +7506,7 @@
         self.LuckValue = 0
         self.TreasureCount = 0
         self.TreasureCountToday = 0
+        self.TreasureCountTodayGold = 0
         self.FreeCountToday = 0
         self.TreasureCntAward = 0
         self.GridLimitCnt = 0
@@ -7516,6 +7519,7 @@
         length = 0
         length += 1
         length += 2
+        length += 4
         length += 4
         length += 4
         length += 2
@@ -7535,6 +7539,7 @@
         data = CommFunc.WriteWORD(data, self.LuckValue)
         data = CommFunc.WriteDWORD(data, self.TreasureCount)
         data = CommFunc.WriteDWORD(data, self.TreasureCountToday)
+        data = CommFunc.WriteDWORD(data, self.TreasureCountTodayGold)
         data = CommFunc.WriteWORD(data, self.FreeCountToday)
         data = CommFunc.WriteDWORD(data, self.TreasureCntAward)
         data = CommFunc.WriteBYTE(data, self.GridLimitCnt)
@@ -7551,6 +7556,7 @@
                                 LuckValue:%d,
                                 TreasureCount:%d,
                                 TreasureCountToday:%d,
+                                TreasureCountTodayGold:%d,
                                 FreeCountToday:%d,
                                 TreasureCntAward:%d,
                                 GridLimitCnt:%d,
@@ -7563,6 +7569,7 @@
                                 self.LuckValue,
                                 self.TreasureCount,
                                 self.TreasureCountToday,
+                                self.TreasureCountTodayGold,
                                 self.FreeCountToday,
                                 self.TreasureCntAward,
                                 self.GridLimitCnt,
@@ -7647,8 +7654,10 @@
     TreasureType = 0    #(BYTE TreasureType)//寻宝类型
     TreasureIndex = 0    #(BYTE TreasureIndex)//寻宝索引
     CostType = 0    #(BYTE CostType)//消耗类型:0-默认仙玉;1-免费次数;2-寻宝道具
-    AddMoneyType = 0    #(BYTE AddMoneyType)// 本次寻宝增加的积分货币类型,可能为0
-    AddMoneyValue = 0    #(WORD AddMoneyValue)// 本次寻宝增加的积分货币值,可能为0
+    AddMoneyType = 0    #(BYTE AddMoneyType)// 本次寻宝额外增加的积分货币类型,可能为0
+    AddMoneyValue = 0    #(WORD AddMoneyValue)// 本次寻宝额外增加的积分货币值,可能为0
+    AddItemID = 0    #(DWORD AddItemID)// 本次寻宝额外赠送的物品ID,可能为0
+    AddItemCount = 0    #(DWORD AddItemCount)// 本次寻宝额外赠送的物品ID个数,可能为0
     AddTreasureLuck = 0    #(WORD AddTreasureLuck)// 本次寻宝增加的幸运值
     TreasureResultLen = 0    #(WORD TreasureResultLen)
     TreasureResult = ""    #(String TreasureResult)//  获得物品结果[[格子编号, 物品ID,个数,是否绑定], ...]
@@ -7668,6 +7677,8 @@
         self.CostType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
         self.AddMoneyType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
         self.AddMoneyValue,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.AddItemID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.AddItemCount,_pos = CommFunc.ReadDWORD(_lpData, _pos)
         self.AddTreasureLuck,_pos = CommFunc.ReadWORD(_lpData, _pos)
         self.TreasureResultLen,_pos = CommFunc.ReadWORD(_lpData, _pos)
         self.TreasureResult,_pos = CommFunc.ReadString(_lpData, _pos,self.TreasureResultLen)
@@ -7683,6 +7694,8 @@
         self.CostType = 0
         self.AddMoneyType = 0
         self.AddMoneyValue = 0
+        self.AddItemID = 0
+        self.AddItemCount = 0
         self.AddTreasureLuck = 0
         self.TreasureResultLen = 0
         self.TreasureResult = ""
@@ -7696,6 +7709,8 @@
         length += 1
         length += 1
         length += 2
+        length += 4
+        length += 4
         length += 2
         length += 2
         length += len(self.TreasureResult)
@@ -7710,6 +7725,8 @@
         data = CommFunc.WriteBYTE(data, self.CostType)
         data = CommFunc.WriteBYTE(data, self.AddMoneyType)
         data = CommFunc.WriteWORD(data, self.AddMoneyValue)
+        data = CommFunc.WriteDWORD(data, self.AddItemID)
+        data = CommFunc.WriteDWORD(data, self.AddItemCount)
         data = CommFunc.WriteWORD(data, self.AddTreasureLuck)
         data = CommFunc.WriteWORD(data, self.TreasureResultLen)
         data = CommFunc.WriteString(data, self.TreasureResultLen, self.TreasureResult)
@@ -7723,6 +7740,8 @@
                                 CostType:%d,
                                 AddMoneyType:%d,
                                 AddMoneyValue:%d,
+                                AddItemID:%d,
+                                AddItemCount:%d,
                                 AddTreasureLuck:%d,
                                 TreasureResultLen:%d,
                                 TreasureResult:%s
@@ -7734,6 +7753,8 @@
                                 self.CostType,
                                 self.AddMoneyType,
                                 self.AddMoneyValue,
+                                self.AddItemID,
+                                self.AddItemCount,
                                 self.AddTreasureLuck,
                                 self.TreasureResultLen,
                                 self.TreasureResult
@@ -17330,259 +17351,108 @@
 
 
 #------------------------------------------------------
-# AA 69 登录活动信息新 #tagMCActLoginNew
+# AA 21 武将登场活动信息 #tagSCActHeroAppearInfo
 
-class  tagMCActLoginNewItem(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(tagMCActLoginNewItem)
-
-    def GetBuffer(self):
-        return string_at(addressof(self), self.GetLength())
-
-    def OutputString(self):
-        DumpString = '''// AA 69 登录活动信息新 //tagMCActLoginNew:
-                                ItemID:%d,
-                                ItemCount:%d,
-                                IsBind:%d
-                                '''\
-                                %(
-                                self.ItemID,
-                                self.ItemCount,
-                                self.IsBind
-                                )
-        return DumpString
-
-
-class  tagMCActLoginNewDay(Structure):
-    DayNum = 0    #(BYTE DayNum)//天编号,从1开始,过期未签到领取的天可消耗货币补签领取
-    Count = 0    #(BYTE Count)// 奖励物品数
-    AwardItemList = list()    #(vector<tagMCActLoginNewItem> AwardItemList)// 奖励物品列表
-    CountEx = 0    #(BYTE CountEx)// 额外奖励物品数
-    AwardItemListEx = list()    #(vector<tagMCActLoginNewItem> AwardItemListEx)//  额外奖励物品列表
-    data = None
-
-    def __init__(self):
-        self.Clear()
-        return
-
-    def ReadData(self, _lpData, _pos=0, _Len=0):
-        self.Clear()
-        self.DayNum,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.Count,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        for i in range(self.Count):
-            temAwardItemList = tagMCActLoginNewItem()
-            _pos = temAwardItemList.ReadData(_lpData, _pos)
-            self.AwardItemList.append(temAwardItemList)
-        self.CountEx,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        for i in range(self.CountEx):
-            temAwardItemListEx = tagMCActLoginNewItem()
-            _pos = temAwardItemListEx.ReadData(_lpData, _pos)
-            self.AwardItemListEx.append(temAwardItemListEx)
-        return _pos
-
-    def Clear(self):
-        self.DayNum = 0
-        self.Count = 0
-        self.AwardItemList = list()
-        self.CountEx = 0
-        self.AwardItemListEx = list()
-        return
-
-    def GetLength(self):
-        length = 0
-        length += 1
-        length += 1
-        for i in range(self.Count):
-            length += self.AwardItemList[i].GetLength()
-        length += 1
-        for i in range(self.CountEx):
-            length += self.AwardItemListEx[i].GetLength()
-
-        return length
-
-    def GetBuffer(self):
-        data = ''
-        data = CommFunc.WriteBYTE(data, self.DayNum)
-        data = CommFunc.WriteBYTE(data, self.Count)
-        for i in range(self.Count):
-            data = CommFunc.WriteString(data, self.AwardItemList[i].GetLength(), self.AwardItemList[i].GetBuffer())
-        data = CommFunc.WriteBYTE(data, self.CountEx)
-        for i in range(self.CountEx):
-            data = CommFunc.WriteString(data, self.AwardItemListEx[i].GetLength(), self.AwardItemListEx[i].GetBuffer())
-        return data
-
-    def OutputString(self):
-        DumpString = '''
-                                DayNum:%d,
-                                Count:%d,
-                                AwardItemList:%s,
-                                CountEx:%d,
-                                AwardItemListEx:%s
-                                '''\
-                                %(
-                                self.DayNum,
-                                self.Count,
-                                "...",
-                                self.CountEx,
-                                "..."
-                                )
-        return DumpString
-
-
-class  tagMCActLoginNew(Structure):
+class  tagSCActHeroAppearInfo(Structure):
     Head = tagHead()
+    ActType = 0    #(BYTE ActType)// 活动类型,用于关联活动相关模块用,如签到、任务等
     ActNum = 0    #(BYTE ActNum)// 活动编号
     StartDate = ""    #(char StartDate[10])// 开始日期 y-m-d
     EndtDate = ""    #(char EndtDate[10])// 结束日期 y-m-d
-    LimitLV = 0    #(WORD LimitLV)// 限制等级
-    RepSignMoneyType = 0    #(BYTE RepSignMoneyType)// 补签消耗货币类型
-    RepSignMoneyValue = 0    #(DWORD RepSignMoneyValue)// 补签消耗货币值
-    AwardExCTGID = 0    #(WORD AwardExCTGID)// 扩展奖励礼包充值ID,大于0时代表可以购买礼包每日登录可领取额外奖励
-    DayCount = 0    #(BYTE DayCount)
-    AwardDayList = list()    #(vector<tagMCActLoginNewDay> AwardDayList)// 奖励天列表
+    CfgID = 0    #(WORD CfgID)// 活动时间表配置ID
     data = None
 
     def __init__(self):
         self.Clear()
         self.Head.Cmd = 0xAA
-        self.Head.SubCmd = 0x69
+        self.Head.SubCmd = 0x21
         return
 
     def ReadData(self, _lpData, _pos=0, _Len=0):
         self.Clear()
         _pos = self.Head.ReadData(_lpData, _pos)
+        self.ActType,_pos = CommFunc.ReadBYTE(_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.RepSignMoneyType,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        self.RepSignMoneyValue,_pos = CommFunc.ReadDWORD(_lpData, _pos)
-        self.AwardExCTGID,_pos = CommFunc.ReadWORD(_lpData, _pos)
-        self.DayCount,_pos = CommFunc.ReadBYTE(_lpData, _pos)
-        for i in range(self.DayCount):
-            temAwardDayList = tagMCActLoginNewDay()
-            _pos = temAwardDayList.ReadData(_lpData, _pos)
-            self.AwardDayList.append(temAwardDayList)
+        self.CfgID,_pos = CommFunc.ReadWORD(_lpData, _pos)
         return _pos
 
     def Clear(self):
         self.Head = tagHead()
         self.Head.Clear()
         self.Head.Cmd = 0xAA
-        self.Head.SubCmd = 0x69
+        self.Head.SubCmd = 0x21
+        self.ActType = 0
         self.ActNum = 0
         self.StartDate = ""
         self.EndtDate = ""
-        self.LimitLV = 0
-        self.RepSignMoneyType = 0
-        self.RepSignMoneyValue = 0
-        self.AwardExCTGID = 0
-        self.DayCount = 0
-        self.AwardDayList = list()
+        self.CfgID = 0
         return
 
     def GetLength(self):
         length = 0
         length += self.Head.GetLength()
         length += 1
+        length += 1
         length += 10
         length += 10
         length += 2
-        length += 1
-        length += 4
-        length += 2
-        length += 1
-        for i in range(self.DayCount):
-            length += self.AwardDayList[i].GetLength()
 
         return length
 
     def GetBuffer(self):
         data = ''
         data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteBYTE(data, self.ActType)
         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.RepSignMoneyType)
-        data = CommFunc.WriteDWORD(data, self.RepSignMoneyValue)
-        data = CommFunc.WriteWORD(data, self.AwardExCTGID)
-        data = CommFunc.WriteBYTE(data, self.DayCount)
-        for i in range(self.DayCount):
-            data = CommFunc.WriteString(data, self.AwardDayList[i].GetLength(), self.AwardDayList[i].GetBuffer())
+        data = CommFunc.WriteWORD(data, self.CfgID)
         return data
 
     def OutputString(self):
         DumpString = '''
                                 Head:%s,
+                                ActType:%d,
                                 ActNum:%d,
                                 StartDate:%s,
                                 EndtDate:%s,
-                                LimitLV:%d,
-                                RepSignMoneyType:%d,
-                                RepSignMoneyValue:%d,
-                                AwardExCTGID:%d,
-                                DayCount:%d,
-                                AwardDayList:%s
+                                CfgID:%d
                                 '''\
                                 %(
                                 self.Head.OutputString(),
+                                self.ActType,
                                 self.ActNum,
                                 self.StartDate,
                                 self.EndtDate,
-                                self.LimitLV,
-                                self.RepSignMoneyType,
-                                self.RepSignMoneyValue,
-                                self.AwardExCTGID,
-                                self.DayCount,
-                                "..."
+                                self.CfgID
                                 )
         return DumpString
 
 
-m_NAtagMCActLoginNew=tagMCActLoginNew()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActLoginNew.Head.Cmd,m_NAtagMCActLoginNew.Head.SubCmd))] = m_NAtagMCActLoginNew
+m_NAtagSCActHeroAppearInfo=tagSCActHeroAppearInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCActHeroAppearInfo.Head.Cmd,m_NAtagSCActHeroAppearInfo.Head.SubCmd))] = m_NAtagSCActHeroAppearInfo
 
 
 #------------------------------------------------------
-# AA 70 登录活动玩家信息新 #tagMCActLoginPlayerInfoNew
+# AA 22 武将登场活动玩家信息 #tagSCActHeroAppearPlayerInfo
 
-class  tagMCActLoginPlayerInfoNew(Structure):
+class  tagSCActHeroAppearPlayerInfo(Structure):
     _pack_ = 1
     _fields_ = [
                   ("Cmd", c_ubyte),
                   ("SubCmd", c_ubyte),
                   ("ActNum", c_ubyte),    # 活动编号
-                  ("LoginAward", c_int),    # 普通奖励领取记录,按天对应二进制位记录是否已领取
-                  ("LoginAwardEx", c_int),    # 额外奖励领取记录,按天对应二进制位记录是否已领取
+                  ("StarHeroIndex", c_ubyte),    # 升星计划选择的武将ID索引
+                  ("StarFreeAward", c_int),    # 升星计划免费奖励记录,按奖励记录索引二进制位运算记录是否已领取
+                  ("CallHeroIndex", c_ubyte),    # 招募选择的武将ID索引
                   ]
 
     def __init__(self):
         self.Clear()
         self.Cmd = 0xAA
-        self.SubCmd = 0x70
+        self.SubCmd = 0x22
         return
 
     def ReadData(self, stringData, _pos=0, _len=0):
@@ -17592,38 +17462,41 @@
 
     def Clear(self):
         self.Cmd = 0xAA
-        self.SubCmd = 0x70
+        self.SubCmd = 0x22
         self.ActNum = 0
-        self.LoginAward = 0
-        self.LoginAwardEx = 0
+        self.StarHeroIndex = 0
+        self.StarFreeAward = 0
+        self.CallHeroIndex = 0
         return
 
     def GetLength(self):
-        return sizeof(tagMCActLoginPlayerInfoNew)
+        return sizeof(tagSCActHeroAppearPlayerInfo)
 
     def GetBuffer(self):
         return string_at(addressof(self), self.GetLength())
 
     def OutputString(self):
-        DumpString = '''// AA 70 登录活动玩家信息新 //tagMCActLoginPlayerInfoNew:
+        DumpString = '''// AA 22 武将登场活动玩家信息 //tagSCActHeroAppearPlayerInfo:
                                 Cmd:%s,
                                 SubCmd:%s,
                                 ActNum:%d,
-                                LoginAward:%d,
-                                LoginAwardEx:%d
+                                StarHeroIndex:%d,
+                                StarFreeAward:%d,
+                                CallHeroIndex:%d
                                 '''\
                                 %(
                                 self.Cmd,
                                 self.SubCmd,
                                 self.ActNum,
-                                self.LoginAward,
-                                self.LoginAwardEx
+                                self.StarHeroIndex,
+                                self.StarFreeAward,
+                                self.CallHeroIndex
                                 )
         return DumpString
 
 
-m_NAtagMCActLoginPlayerInfoNew=tagMCActLoginPlayerInfoNew()
-ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActLoginPlayerInfoNew.Cmd,m_NAtagMCActLoginPlayerInfoNew.SubCmd))] = m_NAtagMCActLoginPlayerInfoNew
+m_NAtagSCActHeroAppearPlayerInfo=tagSCActHeroAppearPlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCActHeroAppearPlayerInfo.Cmd,m_NAtagSCActHeroAppearPlayerInfo.SubCmd))] = m_NAtagSCActHeroAppearPlayerInfo
 
 
 #------------------------------------------------------
@@ -18609,6 +18482,66 @@
 
 
 #------------------------------------------------------
+# AA 20 活动签到奖励信息 #tagSCActSignPlayerInfo
+
+class  tagSCActSignPlayerInfo(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("ActType", c_ubyte),    # 活动类型
+                  ("ActNum", c_ubyte),    # 活动编号
+                  ("SignAward", c_int),    # 奖励领取记录,按天对应二进制位记录是否已领取
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xAA
+        self.SubCmd = 0x20
+        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 = 0x20
+        self.ActType = 0
+        self.ActNum = 0
+        self.SignAward = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagSCActSignPlayerInfo)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// AA 20 活动签到奖励信息 //tagSCActSignPlayerInfo:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                ActType:%d,
+                                ActNum:%d,
+                                SignAward:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.ActType,
+                                self.ActNum,
+                                self.SignAward
+                                )
+        return DumpString
+
+
+m_NAtagSCActSignPlayerInfo=tagSCActSignPlayerInfo()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCActSignPlayerInfo.Cmd,m_NAtagSCActSignPlayerInfo.SubCmd))] = m_NAtagSCActSignPlayerInfo
+
+
+#------------------------------------------------------
 # AA 50 单笔累充活动信息 #tagMCActSingleRechargeInfo
 
 class  tagMCActSingleRechargeAwardItem(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBBillboard.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBBillboard.py
index 910a016..2818ac5 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBBillboard.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBBillboard.py
@@ -128,13 +128,13 @@
     def GetGroupValue1(self): return self.__groupValue1
     def GetGroupValue2(self): return self.__groupValue2
     
-    def ClearData(self):
+    def ClearData(self, drName=""):
         if not self.__billboardList:
             return
-        GameWorld.Log("Billboard ClearData billboardType=%s,groupValue1=%s,groupValue2=%s,dataCount=%s" 
-                      % (self.__billboardType, self.__groupValue1, self.__groupValue2, len(self.__billboardList)))
-        if GameWorld.IsCrossServer():
-            self.SaveDRData("Clear")
+        GameWorld.Log("Billboard ClearData billboardType=%s,groupValue1=%s,groupValue2=%s,dataCount=%s,drName=%s" 
+                      % (self.__billboardType, self.__groupValue1, self.__groupValue2, len(self.__billboardList), drName))
+        if drName or GameWorld.IsCrossServer():
+            self.SaveDRData(drName if drName else "Clear")
         self.__billboardList = [] # [BillboardData, ...] 
         self.__idOrderDict = {} # {id:名次, ...}
         self.__idIndexDict = {}
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
index 80d38e8..cba53e5 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
@@ -117,16 +117,25 @@
         SyncShopItemBuyCntInfo(curPlayer, syncIDList)
     return
 
-def ResetShopItemBuyCountByShopType(curPlayer, shopTypeList):
+def ResetShopItemBuyCountByShopType(curPlayer, shopTypeList, recycleItemMail=""):
     ##根据商店类型重置商店限购物品次数
+    # @param recycleItemMail: 商店消耗物品回收通知邮件,为空时不回收
     if not shopTypeList:
         return
+    recycleCostItemIDList = []
     syncIDList = []
     for shopType in shopTypeList:
         ipyDataList = IpyGameDataPY.GetIpyGameDataByCondition("Store", {"ShopType":shopType}, True, True)
         if not ipyDataList:
             continue
         for ipyData in ipyDataList:
+            
+            # 消耗道具回收
+            costItemID = ipyData.GetCostItemID()
+            if recycleItemMail and costItemID and costItemID not in recycleCostItemIDList:
+                recycleCostItemIDList.append(costItemID)
+                ItemControler.RecycleItem(curPlayer, costItemID, recycleItemMail)
+                
             if not ipyData.GetLimitCnt():
                 continue
             shopID = ipyData.GetID()
@@ -258,6 +267,7 @@
         GameWorld.Log("Store shop item lock! shopID=%s,shopID=%s" % (shopType, shopID), curPlayer.GetPlayerID())
         return
     
+    costItemID = ipyData.GetCostItemID()
     priceType, itemPrice = ipyData.GetMoneyType(), ipyData.GetMoneyNum()
     itemPrice *= clientBuyCount
     #if not PlayerControl.HaveMoney(curPlayer, priceType, itemPrice):
@@ -265,9 +275,19 @@
     
     infoDict = {"TotalItemList":totalItemList, "ClientBuyCount":clientBuyCount, "ShopType":shopType,
                 "ShopID":shopID, ChConfig.Def_Cost_Reason_SonKey:mainItemID}
-    if priceType and itemPrice and not PlayerControl.PayMoney(curPlayer, priceType, itemPrice, ChConfig.Def_Cost_BuyStoreItem, infoDict, clientBuyCount):
-        return
-    
+    # 支持消耗货币或道具二选一
+    if priceType:
+        if itemPrice and not PlayerControl.PayMoney(curPlayer, priceType, itemPrice, ChConfig.Def_Cost_BuyStoreItem, infoDict, clientBuyCount):
+            return
+    elif costItemID and itemPrice:
+        needItemCnt = itemPrice
+        costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, costItemID, needItemCnt)
+        lackCnt = needItemCnt - bindCnt - unBindCnt
+        if lackCnt > 0:
+            GameWorld.DebugLog("所需消耗道具不足! costItemID=%s,needItemCnt=%s,lackCnt=%s" % (costItemID, needItemCnt, lackCnt))
+            return
+        ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, needItemCnt, "BuyItem")
+        
     # 今日购买次数+1
     if limitBuyCnt > 0:
         updBuyCnt = min(curBuyCnt + clientBuyCount, ChConfig.Def_UpperLimit_DWord)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Billboard.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Billboard.py
index 309a4f3..ceb798d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Billboard.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/Billboard.py
@@ -29,10 +29,8 @@
     GameWorld.DebugAnswer(curPlayer, "输出排行榜数据: Billboard p 类型 [分组值1 值2 从x名 到x名]")
     GameWorld.DebugAnswer(curPlayer, "注:如果没有特殊说明,本服榜单分组值均为0,跨服榜单分组值1为分区ID,分组2为0")
     
-    nameTypeList = ShareDefine.BillboardNameDict.keys()
-    nameTypeList.sort()
-    for billboardType in nameTypeList:
-        bName = ShareDefine.BillboardNameDict[billboardType]
+    for billboardType in ShareDefine.BillboardTypeList:
+        bName = ShareDefine.BillboardNameDict.get(billboardType, billboardType)
         GameWorld.DebugAnswer(curPlayer, "(%s) %s" % (billboardType, bName))
         
     return
@@ -157,8 +155,9 @@
                 maxDataCount = billboardObj.GetMaxCount()
                 if not curDataCount:
                     continue
+                bName = ShareDefine.BillboardNameDict.get(bType, bType)
                 billTypeSign = __GetBillTypeSign(bType, groupValue1, groupValue2)
-                GameWorld.DebugAnswer(curPlayer, "榜单数据(%s)条数: %s/%s" % (billTypeSign, curDataCount, maxDataCount))
+                GameWorld.DebugAnswer(curPlayer, "%s(%s)条数: %s/%s" % (bName, billTypeSign, curDataCount, maxDataCount))
         return
     
     billboardType = gmList[1]
@@ -175,7 +174,7 @@
     
     printDebugCnt = 0
     billTypeSign = __GetBillTypeSign(billboardType, groupValue1, groupValue2)
-    bName = ShareDefine.BillboardNameDict[billboardType]
+    bName = ShareDefine.BillboardNameDict.get(billboardType, billboardType)
     GameWorld.DebugAnswer(curPlayer, "%s(%s)条数: %s/%s 详见日志" % (bName, billTypeSign, curDataCount, maxDataCount))
     for index in range(curDataCount):
         bbData = billboardObj.At(index)
@@ -188,7 +187,7 @@
         valueList = [getattr(bbData, "GetValue%s" % num)() for num in range(1, 9)]
         if printDebugCnt < 20:
             printDebugCnt += 1
-            GameWorld.DebugAnswer(curPlayer, "%s,ID:%s,榜值:%s" % (rank, dataID, cmpValues))
+            GameWorld.DebugAnswer(curPlayer, "名次:%s,ID:%s,榜值:%s" % (rank, dataID, cmpValues))
         GameWorld.DebugLog("%s,rank=%s,ID=%s,CmpValues=%s,Value=%s" 
                            % (index, rank, dataID, cmpValues, valueList), curPlayer.GetPlayerID())
         
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetXunbao.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetXunbao.py
index 558a5b2..59e3d7b 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetXunbao.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetXunbao.py
@@ -32,7 +32,7 @@
     if not paramList:
         GameWorld.DebugAnswer(curPlayer, "重置寻宝:SetXunbao 0 [指定类型]")
         GameWorld.DebugAnswer(curPlayer, "设置幸运:SetXunbao l 类型 幸运")
-        GameWorld.DebugAnswer(curPlayer, "设置次数:SetXunbao c 类型 今日次数 [累计次数]")
+        GameWorld.DebugAnswer(curPlayer, "设置次数:SetXunbao c 类型 今日次数 [累计次数 货币次数]")
         return
     
     value = paramList[0]
@@ -65,6 +65,7 @@
         treasureType = paramList[1] if len(paramList) > 1 else None
         treasureCountToday = paramList[2] if len(paramList) > 2 else None
         treasureCount = paramList[3] if len(paramList) > 3 else None
+        treasureCountTodayGold = paramList[4] if len(paramList) > 4 else None
         if not IpyGameDataPY.GetIpyGameData("TreasureSet", treasureType):
             GameWorld.DebugAnswer(curPlayer, "寻宝类型不存在!%s" % treasureType)
             return
@@ -74,6 +75,9 @@
         if treasureCount != None:
             PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCount % (treasureType), treasureCount)
             GameWorld.DebugAnswer(curPlayer, "设置寻宝类型=%s,累计次数=%s" % (treasureType, treasureCount))
+        if treasureCountTodayGold != None:
+            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCountTodayGold % (treasureType), treasureCountTodayGold)
+            GameWorld.DebugAnswer(curPlayer, "设置寻宝类型=%s,今日元宝次数=%s" % (treasureType, treasureCountTodayGold))
         syncTypeList = [treasureType]
         
     PlayerTreasure.Sync_TreasureInfo(curPlayer, syncTypeList)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldAction.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldAction.py
index e3f212d..c0ce69b 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldAction.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldAction.py
@@ -19,6 +19,7 @@
 import DBDataMgr
 import ShareDefine
 import PlayerActLunhuidian
+import PlayerActHeroAppear
 import IpyGameDataPY
 import PlayerControl
 import PyGameData
@@ -701,11 +702,16 @@
             dbOperationActIDKey = ShareDefine.Def_OperationActID % (actName, actNum)
             dbActID = dbEventMgr.GetValue(dbOperationActIDKey)
             
+            dbOperationActCfgIDKey = ShareDefine.Def_OperationActCfgID % (actName, actNum)
+            dbActCfgID = dbEventMgr.GetValue(dbOperationActCfgIDKey)
+            
             curActID = sendMapServerMsgDict.get(ShareDefine.ActKey_ID, 0)
+            curCfgID = sendMapServerMsgDict.get(ShareDefine.ActKey_CfgID, 0)
             #dayIndex = sendMapServerMsgDict.get(ShareDefine.ActKey_DayIndex, 0)
             if dbActID != curActID:
-                GameWorld.Log("    dbActID变更: dbActID=%s,curActID=%s" % (dbActID, curActID))
+                GameWorld.Log("    dbActID变更: dbActID=%s,curActID=%s,dbActCfgID=%s,curCfgID=%s" % (dbActID, curActID, dbActCfgID, curCfgID))
                 dbEventMgr.SetValue(dbOperationActIDKey, curActID)
+                dbEventMgr.SetValue(dbOperationActCfgIDKey, curCfgID)
                 
                 # 结束旧的
                 if dbActID:
@@ -722,15 +728,17 @@
                 #else:
                 #    if actName == ShareDefine.OperationActionName_GarbageSorting:
                 #        PlayerActGarbageSorting.OnActEnd(actNum)
-                        
+                
+                if actName == ShareDefine.OperationActionName_HeroAppear:
+                    PlayerActHeroAppear.OnActIDChange(actNum, ipyData, state, dbActCfgID)
+                    
             else:
-                GameWorld.Log("    dbActID不变: dbActID=%s,curActID=%s" % (dbActID, curActID))
+                GameWorld.Log("    dbActID不变: dbActID=%s,curActID=%s,dbActCfgID=%s" % (dbActID, curActID, dbActCfgID))
                 
             # 活动中刷新,每次都需要刷新的逻辑,包含重读配置等
             if state:
-                pass
-                #if actName == ShareDefine.OperationActionName_Gubao:
-                #    PlayerActGubao.OnActInStateRefresh(actNum, ipyData)
+                if actName == ShareDefine.OperationActionName_HeroAppear:
+                    PlayerActHeroAppear.OnActInStateRefresh(actNum, ipyData)
                     
             # 仅活动有配置参与时间段的会触发
             if curActID and dbActID == curActID and preStateJoin != stateJoin:
@@ -769,6 +777,8 @@
     GameWorld.Log("OperationActionRefresh: %s,actNum=%s,%s" % (actName, actNum, actInfo))
     if actName == ShareDefine.OperationActionName_Lunhuidian:
         PlayerActLunhuidian.RefreshActLunhuidianActionInfo(actNum)
+    elif actName == ShareDefine.OperationActionName_HeroAppear:
+        PlayerActHeroAppear.RefreshActHeroAppearActionInfo(actNum)
         
     return
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index 8f85a04..8257d1d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1008,6 +1008,7 @@
                         ("list", "ItemListEx", 0),
                         ("BYTE", "ResetType", 0),
                         ("DWORD", "LimitCnt", 0),
+                        ("DWORD", "CostItemID", 0),
                         ("BYTE", "MoneyType", 0),
                         ("DWORD", "MoneyNum", 0),
                         ("DWORD", "MoneyOriginal", 0),
@@ -1173,10 +1174,10 @@
 
                 "TreasureSet":(
                         ("BYTE", "TreasureType", 1),
-                        ("BYTE", "PackType", 0),
-                        ("BYTE", "CheckPack", 0),
-                        ("BYTE", "IsActType", 0),
+                        ("list", "CheckPackList", 0),
+                        ("BYTE", "ActType", 0),
                         ("DWORD", "DailyMaxCount", 0),
+                        ("DWORD", "DailyMaxCountMoney", 0),
                         ("BYTE", "DailyFreeCount", 0),
                         ("list", "TreasureCountList", 0),
                         ("char", "RecycleItemMail", 0),
@@ -1189,10 +1190,12 @@
                         ("char", "LuckyRateFormat", 0),
                         ("BYTE", "LuckyGridNum", 0),
                         ("dict", "GridNumMaxLimitInfo", 0),
+                        ("list", "RecordGridNumList", 0),
                         ("list", "NotifyGridNumList", 0),
                         ("dict", "NotifyKeyDict", 0),
                         ("BYTE", "AwardMoneyType", 0),
                         ("WORD", "AwardMoneyValue", 0),
+                        ("list", "AwardItemInfo", 0),
                         ("BYTE", "WishReset", 0),
                         ("dict", "WishLibSelect", 0),
                         ("dict", "WishLibPubFreeCnt", 0),
@@ -1514,25 +1517,47 @@
                         ("list", "AwardItemList", 0),
                         ),
 
-                "ActLoginNew":(
-                        ("DWORD", "CfgID", 1),
-                        ("char", "StartDate", 0),
-                        ("char", "EndDate", 0),
-                        ("WORD", "RelateFuncID", 0),
-                        ("BYTE", "FuncActDays", 0),
-                        ("BYTE", "FuncLoop", 0),
-                        ("WORD", "LVLimit", 0),
-                        ("list", "RepSignCostMoneyInfo", 0),
-                        ("BYTE", "TemplateID", 0),
-                        ("WORD", "AwardExCTGID", 0),
-                        ("WORD", "ActZhanlingType", 0),
-                        ),
-
-                "ActLoginNewAward":(
+                "ActSignAward":(
                         ("BYTE", "TemplateID", 1),
                         ("BYTE", "DayNum", 0),
-                        ("list", "LoginAwardItemList", 0),
-                        ("list", "LoginAwardItemListEx", 0),
+                        ("list", "SignAwardItemList", 0),
+                        ),
+
+                "ActBillboardAward":(
+                        ("DWORD", "TemplateID", 1),
+                        ("WORD", "RankA", 0),
+                        ("WORD", "RankB", 0),
+                        ("float", "NeedValue", 0),
+                        ("list", "AwardItemList", 0),
+                        ),
+
+                "ActHeroAppear":(
+                        ("DWORD", "CfgID", 1),
+                        ("list", "PlatformList", 0),
+                        ("list", "ServerIDList", 0),
+                        ("BYTE", "ActNum", 0),
+                        ("char", "StartDate", 0),
+                        ("char", "EndDate", 0),
+                        ("list", "ActHeroIDList", 0),
+                        ("WORD", "ActTreasureType", 0),
+                        ("BYTE", "StarGiftTempID", 0),
+                        ("list", "SkinCTGIDList", 0),
+                        ("list", "GiftCTGIDList", 0),
+                        ("WORD", "GiftShopType", 0),
+                        ("WORD", "ExShopType", 0),
+                        ("char", "ExShopRecycleMail", 0),
+                        ("WORD", "SignTempID", 0),
+                        ("WORD", "BillTempID", 0),
+                        ("char", "BillAwardMail", 0),
+                        ),
+
+                "ActHeroAppearStar":(
+                        ("BYTE", "StarTempID", 1),
+                        ("BYTE", "NeedStar", 0),
+                        ("BYTE", "AwardIndex", 0),
+                        ("list", "FreeAwardItemList", 0),
+                        ("WORD", "StarGiftCTGID", 0),
+                        ("dict", "HeroGiftItemInfo", 0),
                         ),
 
                 "EquipPlaceIndexMap":(
@@ -3157,11 +3182,12 @@
     def GetItemListEx(self): return self.attrTuple[4] # 扩展物品列表[[物品ID,个数,是否绑定],...] list
     def GetResetType(self): return self.attrTuple[5] # 重置类型 BYTE
     def GetLimitCnt(self): return self.attrTuple[6] # 个人限制数量 DWORD
-    def GetMoneyType(self): return self.attrTuple[7] # 金钱类型 BYTE
-    def GetMoneyNum(self): return self.attrTuple[8] # 金钱数量 DWORD
-    def GetMoneyOriginal(self): return self.attrTuple[9] # 原价 DWORD
-    def GetUnlockType(self): return self.attrTuple[10] # 解锁类型 BYTE
-    def GetUnlockValue(self): return self.attrTuple[11] # 解锁所需值 DWORD
+    def GetCostItemID(self): return self.attrTuple[7] # 消耗道具ID DWORD
+    def GetMoneyType(self): return self.attrTuple[8] # 金钱类型 BYTE
+    def GetMoneyNum(self): return self.attrTuple[9] # 金钱数量 DWORD
+    def GetMoneyOriginal(self): return self.attrTuple[10] # 原价 DWORD
+    def GetUnlockType(self): return self.attrTuple[11] # 解锁类型 BYTE
+    def GetUnlockValue(self): return self.attrTuple[12] # 解锁所需值 DWORD
 
 # 每日任务表
 class IPY_DailyTask():
@@ -3397,10 +3423,10 @@
         return
         
     def GetTreasureType(self): return self.attrTuple[0] # 寻宝类型 BYTE
-    def GetPackType(self): return self.attrTuple[1] # 放入背包 BYTE
-    def GetCheckPack(self): return self.attrTuple[2] # 是否检查背包 BYTE
-    def GetIsActType(self): return self.attrTuple[3] # 是否活动寻宝 BYTE
-    def GetDailyMaxCount(self): return self.attrTuple[4] # 每日最大次数 DWORD
+    def GetCheckPackList(self): return self.attrTuple[1] # 检查背包类型列表 list
+    def GetActType(self): return self.attrTuple[2] # 活动寻宝类型 BYTE
+    def GetDailyMaxCount(self): return self.attrTuple[3] # 每日最大次数 DWORD
+    def GetDailyMaxCountMoney(self): return self.attrTuple[4] # 每日货币次数 DWORD
     def GetDailyFreeCount(self): return self.attrTuple[5] # 每日免费次数 BYTE
     def GetTreasureCountList(self): return self.attrTuple[6] # 抽奖次数列表 list
     def GetRecycleItemMail(self): return self.attrTuple[7] # 重置回收道具邮件,如果有配置回收邮件key,则重置时会回收多余的寻宝道具 char
@@ -3413,14 +3439,16 @@
     def GetLuckyRateFormat(self): return self.attrTuple[14] # 幸运格子概率公式 char
     def GetLuckyGridNum(self): return self.attrTuple[15] # 幸运格子编号 BYTE
     def GetGridNumMaxLimitInfo(self): return self.attrTuple[16] # 格子最大产出次数限制,{"格子":最大可产出次数, ...} dict
-    def GetNotifyGridNumList(self): return self.attrTuple[17] # 需要额外广播的格子 list
-    def GetNotifyKeyDict(self): return self.attrTuple[18] # 广播key dict
-    def GetAwardMoneyType(self): return self.attrTuple[19] # 额外奖励货币类型 BYTE
-    def GetAwardMoneyValue(self): return self.attrTuple[20] # 单次奖励货币数 WORD
-    def GetWishReset(self): return self.attrTuple[21] # 心愿重置规则 BYTE
-    def GetWishLibSelect(self): return self.attrTuple[22] # 心愿库选择数 dict
-    def GetWishLibPubFreeCnt(self): return self.attrTuple[23] # 心愿库公共免费次数 dict
-    def GetWishLibCard(self): return self.attrTuple[24] # 心愿库心愿卡 dict
+    def GetRecordGridNumList(self): return self.attrTuple[17] # 需要记录产出的格子 list
+    def GetNotifyGridNumList(self): return self.attrTuple[18] # 需要额外广播的格子 list
+    def GetNotifyKeyDict(self): return self.attrTuple[19] # 广播key dict
+    def GetAwardMoneyType(self): return self.attrTuple[20] # 额外奖励货币类型 BYTE
+    def GetAwardMoneyValue(self): return self.attrTuple[21] # 单次奖励货币数 WORD
+    def GetAwardItemInfo(self): return self.attrTuple[22] # 单次额外奖励道具,物品ID|个数 list
+    def GetWishReset(self): return self.attrTuple[23] # 心愿重置规则 BYTE
+    def GetWishLibSelect(self): return self.attrTuple[24] # 心愿库选择数 dict
+    def GetWishLibPubFreeCnt(self): return self.attrTuple[25] # 心愿库公共免费次数 dict
+    def GetWishLibCard(self): return self.attrTuple[26] # 心愿库心愿卡 dict
 
 # 寻宝产出库表
 class IPY_TreasureHouse():
@@ -3912,27 +3940,8 @@
     def GetNeedValue(self): return self.attrTuple[3] # 完成任务所需值 DWORD
     def GetAwardItemList(self): return self.attrTuple[4] # 任务奖励列表[[物品ID,个数,是否拍品], ...] list
 
-# 登录活动奖励时间表新
-class IPY_ActLoginNew():
-    
-    def __init__(self):
-        self.attrTuple = None
-        return
-        
-    def GetCfgID(self): return self.attrTuple[0] # 配置ID DWORD
-    def GetStartDate(self): return self.attrTuple[1] # 开启日期 char
-    def GetEndDate(self): return self.attrTuple[2] # 结束日期 char
-    def GetRelateFuncID(self): return self.attrTuple[3] # 关联功能ID WORD
-    def GetFuncActDays(self): return self.attrTuple[4] # 功能活动天数 BYTE
-    def GetFuncLoop(self): return self.attrTuple[5] # 功能是否循环 BYTE
-    def GetLVLimit(self): return self.attrTuple[6] # 限制等级 WORD
-    def GetRepSignCostMoneyInfo(self): return self.attrTuple[7] # 补签消耗货币类型数量 list
-    def GetTemplateID(self): return self.attrTuple[8] # 登录奖励模板编号 BYTE
-    def GetAwardExCTGID(self): return self.attrTuple[9] # 扩展奖励礼包充值ID WORD
-    def GetActZhanlingType(self): return self.attrTuple[10] # 关联活动战令类型 WORD
-
-# 登录活动奖励模板表新
-class IPY_ActLoginNewAward():
+# 活动签到奖励表
+class IPY_ActSignAward():
     
     def __init__(self):
         self.attrTuple = None
@@ -3940,8 +3949,59 @@
         
     def GetTemplateID(self): return self.attrTuple[0] # 模板ID BYTE
     def GetDayNum(self): return self.attrTuple[1] # 第X天从1开始 BYTE
-    def GetLoginAwardItemList(self): return self.attrTuple[2] # 奖励列表[[物品ID,个数,是否拍品], ...] list
-    def GetLoginAwardItemListEx(self): return self.attrTuple[3] # 扩展奖励列表[[物品ID,个数,是否拍品], ...] list
+    def GetSignAwardItemList(self): return self.attrTuple[2] # 奖励列表[[物品ID,个数], ...] list
+
+# 活动排行奖励表
+class IPY_ActBillboardAward():
+    
+    def __init__(self):
+        self.attrTuple = None
+        return
+        
+    def GetTemplateID(self): return self.attrTuple[0] # 模板ID DWORD
+    def GetRankA(self): return self.attrTuple[1] # 名次A WORD
+    def GetRankB(self): return self.attrTuple[2] # 至名次B WORD
+    def GetNeedValue(self): return self.attrTuple[3] # 至少所需值 float
+    def GetAwardItemList(self): return self.attrTuple[4] # 奖励物品列表[[物品ID,个数], ...] list
+
+# 武将登场时间表
+class IPY_ActHeroAppear():
+    
+    def __init__(self):
+        self.attrTuple = None
+        return
+        
+    def GetCfgID(self): return self.attrTuple[0] # 配置ID DWORD
+    def GetPlatformList(self): return self.attrTuple[1] # 活动平台列表["平台A", "平台A", ...],配[]代表所有 list
+    def GetServerIDList(self): return self.attrTuple[2] # 服务器ID列表 list
+    def GetActNum(self): return self.attrTuple[3] # 活动分组编号, 活动类型 * 10 + 不同界面编号 BYTE
+    def GetStartDate(self): return self.attrTuple[4] # 开启日期 char
+    def GetEndDate(self): return self.attrTuple[5] # 结束日期 char
+    def GetActHeroIDList(self): return self.attrTuple[6] # 登场武将ID列表 list
+    def GetActTreasureType(self): return self.attrTuple[7] # 招募寻宝类型 WORD
+    def GetStarGiftTempID(self): return self.attrTuple[8] # 专属升星礼包模板 BYTE
+    def GetSkinCTGIDList(self): return self.attrTuple[9] # 时装充值ID列表 list
+    def GetGiftCTGIDList(self): return self.attrTuple[10] # 礼包充值ID列表 list
+    def GetGiftShopType(self): return self.attrTuple[11] # 礼包商店类型 WORD
+    def GetExShopType(self): return self.attrTuple[12] # 兑换商店类型 WORD
+    def GetExShopRecycleMail(self): return self.attrTuple[13] # 兑换货币回收邮件 char
+    def GetSignTempID(self): return self.attrTuple[14] # 签到奖励模板 WORD
+    def GetBillTempID(self): return self.attrTuple[15] # 排行奖励模板 WORD
+    def GetBillAwardMail(self): return self.attrTuple[16] # 榜单奖励发放邮件 char
+
+# 升星计划奖励表
+class IPY_ActHeroAppearStar():
+    
+    def __init__(self):
+        self.attrTuple = None
+        return
+        
+    def GetStarTempID(self): return self.attrTuple[0] # 模板ID BYTE
+    def GetNeedStar(self): return self.attrTuple[1] # 所需星 BYTE
+    def GetAwardIndex(self): return self.attrTuple[2] # 奖励记录索引 BYTE
+    def GetFreeAwardItemList(self): return self.attrTuple[3] # 免费奖励物品信息列表[[物品ID,个数], ...] list
+    def GetStarGiftCTGID(self): return self.attrTuple[4] # 星级礼包充值ID WORD
+    def GetHeroGiftItemInfo(self): return self.attrTuple[5] # 登场武将额外专属奖励信息{"武将ID":[[专属物品ID,个数], ...], ...} dict
 
 # 装备位背包索引映射表
 class IPY_EquipPlaceIndexMap():
@@ -4446,8 +4506,10 @@
         self.__LoadFileData("ActBuyCountGift", onlyCheck)
         self.__LoadFileData("ActTask", onlyCheck)
         self.__LoadFileData("ActTaskTemp", onlyCheck)
-        self.__LoadFileData("ActLoginNew", onlyCheck)
-        self.__LoadFileData("ActLoginNewAward", onlyCheck)
+        self.__LoadFileData("ActSignAward", onlyCheck)
+        self.__LoadFileData("ActBillboardAward", onlyCheck)
+        self.__LoadFileData("ActHeroAppear", onlyCheck)
+        self.__LoadFileData("ActHeroAppearStar", onlyCheck)
         self.__LoadFileData("EquipPlaceIndexMap", onlyCheck)
         self.__LoadFileData("EquipShenAttr", onlyCheck)
         self.__LoadFileData("EquipShenEvolve", onlyCheck)
@@ -5684,19 +5746,33 @@
         self.CheckLoadData("ActTaskTemp")
         return self.ipyActTaskTempCache[index]
 
-    def GetActLoginNewCount(self):
-        self.CheckLoadData("ActLoginNew")
-        return self.ipyActLoginNewLen
-    def GetActLoginNewByIndex(self, index):
-        self.CheckLoadData("ActLoginNew")
-        return self.ipyActLoginNewCache[index]
+    def GetActSignAwardCount(self):
+        self.CheckLoadData("ActSignAward")
+        return self.ipyActSignAwardLen
+    def GetActSignAwardByIndex(self, index):
+        self.CheckLoadData("ActSignAward")
+        return self.ipyActSignAwardCache[index]
 
-    def GetActLoginNewAwardCount(self):
-        self.CheckLoadData("ActLoginNewAward")
-        return self.ipyActLoginNewAwardLen
-    def GetActLoginNewAwardByIndex(self, index):
-        self.CheckLoadData("ActLoginNewAward")
-        return self.ipyActLoginNewAwardCache[index]
+    def GetActBillboardAwardCount(self):
+        self.CheckLoadData("ActBillboardAward")
+        return self.ipyActBillboardAwardLen
+    def GetActBillboardAwardByIndex(self, index):
+        self.CheckLoadData("ActBillboardAward")
+        return self.ipyActBillboardAwardCache[index]
+
+    def GetActHeroAppearCount(self):
+        self.CheckLoadData("ActHeroAppear")
+        return self.ipyActHeroAppearLen
+    def GetActHeroAppearByIndex(self, index):
+        self.CheckLoadData("ActHeroAppear")
+        return self.ipyActHeroAppearCache[index]
+
+    def GetActHeroAppearStarCount(self):
+        self.CheckLoadData("ActHeroAppearStar")
+        return self.ipyActHeroAppearStarLen
+    def GetActHeroAppearStarByIndex(self, index):
+        self.CheckLoadData("ActHeroAppearStar")
+        return self.ipyActHeroAppearStarCache[index]
 
     def GetEquipPlaceIndexMapCount(self):
         self.CheckLoadData("EquipPlaceIndexMap")
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 5c90268..42129e6 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
@@ -32,6 +32,7 @@
 import PlayerGubao
 import PyGameData
 import PlayerHero
+import PlayerMail
 
 import math
 import time
@@ -2371,7 +2372,7 @@
             
     if notifyMailKey:
         paramList = [itemID, itemID, recycleCount]
-        PlayerControl.SendMailByKey(notifyMailKey, [playerID], addItemList, paramList)
+        PlayerMail.SendMailByKey(notifyMailKey, playerID, addItemList, paramList)
     elif addItemList:
         GivePlayerItemOrMail(curPlayer, addItemList, event=["RecycleItem", False, {"RecycleItemID":itemID}])
         
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 fba04fb..c18a1dc 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -48,7 +48,6 @@
 import PlayerTreasure
 import IpyGameDataPY
 import EventReport
-import PassiveBuffEffMng
 import PlayerActBuyOne
 import PlayerActCollectWords
 import PlayerActTotalRecharge
@@ -62,7 +61,6 @@
 import PyGameData
 import PlayerCoin
 import PlayerFB
-import SkillShell
 import PlayerGubao
 import PlayerCustomAward
 import PlayerZhanling
@@ -71,16 +69,17 @@
 import PlayerTask
 import GameObj
 import PlayerGoldRush
-import PlayerActLoginNew
+import PlayerActSign
 import PlayerActBuyCountGift
 import PlayerActLunhuidian
+import PlayerActHeroAppear
 import PlayerActFamilyGCZ
 import PlayerActTask
 import PlayerMail
 import DBDataMgr
 import PlayerViewCache
 import UpdatePlayerName
-import GameServerRefresh
+#import GameServerRefresh
 import IPY_ServerDefine
 import IPY_PlayerDefine
 import CommFunc
@@ -332,8 +331,6 @@
     PlayerActBuyCountGift.OnPlayerLogin(curPlayer)
     # 任务活动
     PlayerActTask.OnPlayerLogin(curPlayer)
-    # 登录活动
-    PlayerActLoginNew.OnPlayerLogin(curPlayer)
     # 炼器活动
     PlayerActLianqi.OnPlayerLogin(curPlayer)
     # 多日连充活动
@@ -420,6 +417,7 @@
         PlayerPreset.OnPlayerLogin(curPlayer)
         CrossPlayer.OnPlayerLogin(curPlayer)
         PlayerActLunhuidian.OnPlayerLogin(curPlayer)
+        PlayerActHeroAppear.OnPlayerLogin(curPlayer)
         
         __OnFixVersion(curPlayer) # 修正线上玩家数据用,暂时放最后
         # 上线查询一次充值订单
@@ -3137,8 +3135,14 @@
     # 轮回殿奖励
     elif rewardType == ChConfig.Def_RewardType_LunhuidianAward:
         PlayerActLunhuidian.GetLunhuidianAward(curPlayer, dataEx, dataExStr)
+    # 武将登场升星计划免费奖励 10
+    elif rewardType == ChConfig.Def_RewardType_ActHeroAppearStarFreeAward:
+        PlayerActHeroAppear.GetHeroAppearStarFreeAward(curPlayer, dataEx)
+    # 领取活动签到奖励 70
+    elif rewardType == ChConfig.Def_RewardType_ActSignAward:
+        PlayerActSign.OnGetActSignAward(curPlayer, dataEx, dataExStr)
         
-    
+        
     # 首充礼包奖励
     elif rewardType == ChConfig.Def_RewardType_FirstCharge:
         PlayerGoldGift.GetPlayerFirstCharge(curPlayer, dataEx, dataExStr)
@@ -3151,9 +3155,6 @@
     # 领取单笔累充领取
     elif rewardType == ChConfig.Def_RewardType_SingleRecharge:
         PlayerActSingleRecharge.OnGetSingleRechargeAward(curPlayer, dataEx, dataExStr)
-    # 领取登录活动奖励
-    elif rewardType == ChConfig.Def_RewardType_ActLoginAwardNew:
-        PlayerActLoginNew.OnGetActLoginAward(curPlayer, dataEx, dataExStr)
     # 领取购买次数礼包活动
     elif rewardType == ChConfig.Def_RewardType_ActBuyCountGift:
         PlayerActBuyCountGift.OnGetBuyCountGiftAward(curPlayer, dataEx, dataExStr)
@@ -3872,14 +3873,17 @@
     if recType in ShareDefine.Def_ViewGameRecSelfList:
         recID = curPlayer.GetPlayerID()
     recTypeIDMgr = DBDataMgr.GetGameRecMgr().GetRecTypeIDMgr(recType, recID)
-    SyncGameRecInfo(curPlayer, recType, recID, recTypeIDMgr.GetDataList())
+    SyncGameRecInfo(curPlayer, recTypeIDMgr.GetDataList(), recType, recID)
     return
 
-def SyncGameRecInfo(curPlayer, recType, recID, recDataList):
+def SyncGameRecInfo(curPlayer, recDataList, recType=0, recID=0):
     recList = []
     for recData in recDataList:
         if not recData:
             continue
+        if not recType:
+            recType = recData.GetRecType()
+            recID = recData.GetRecID()
         rec = ChPyNetSendPack.tagSCGameRec()
         rec.Time = recData.GetTime()
         rec.Value1 = recData.GetValue1()
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameFuncComm.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameFuncComm.py
index bbbc8ca..1eea137 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameFuncComm.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/GameFuncComm.py
@@ -30,7 +30,6 @@
 import FunctionNPCCommon
 import PlayerActBuyCountGift
 import OpenServerActivity
-import PlayerActLoginNew
 import PlayerActTask
 import ItemControler
 import PlayerMingge
@@ -117,7 +116,6 @@
     if openFuncIDList:
         Sync_FuncOpenState(curPlayer, openFuncIDList)
         PlayerActTask.OnCheckRelateFuncAct(curPlayer, openFuncIDList)
-        PlayerActLoginNew.OnCheckRelateFuncAct(curPlayer, openFuncIDList)
         PlayerActBuyCountGift.OnCheckRelateFuncAct(curPlayer, openFuncIDList)
         
     return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActHeroAppear.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActHeroAppear.py
new file mode 100644
index 0000000..b210130
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActHeroAppear.py
@@ -0,0 +1,379 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerActHeroAppear
+#
+# @todo:武将登场
+# @author hxp
+# @date 2026-02-26
+# @version 1.0
+#
+# 详细描述: 武将登场
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2026-02-26 16:00"""
+#-------------------------------------------------------------------------------
+
+import PyGameData
+import ShareDefine
+import PlayerControl
+import IpyGameDataPY
+import PlayerActSign
+import ChPyNetSendPack
+import FunctionNPCCommon
+import PlayerBillboard
+import PlayerTreasure
+import NetPackCommon
+import ItemControler
+import PlayerHero
+import PlayerCoin
+import GameWorld
+import DBDataMgr
+import ChConfig
+
+def OnActIDChange(actNum, ipyData, state, dbActCfgID):
+    ## 活动ID变更
+    
+    if dbActCfgID:
+        __onActEnd(actNum, dbActCfgID)
+        
+    if state:
+        __onActStart(actNum, ipyData)
+        
+    return
+
+def OnActInStateRefresh(actNum, ipyData):
+    ## 活动中刷新,每次都需要刷新的逻辑,包含重读配置等
+    if not ipyData:
+        return
+    templateID = ipyData.GetBillTempID()
+    
+    # 刷新排名规则
+    PlayerBillboard.SetOrderRuleListByActTempID(ShareDefine.Def_BT_ActHeroAppear, templateID, groupValue1=actNum)
+    return
+
+def __onActStart(actNum, ipyData):
+    ## 活动开启
+    billboardMgr = DBDataMgr.GetBillboardMgr()
+    billboardObj = billboardMgr.GetBillboard(ShareDefine.Def_BT_ActHeroAppear, groupValue1=actNum)
+    billboardObj.ClearData() # 新活动重置榜单数据
+    return
+
+def __onActEnd(actNum, dbActCfgID):
+    ## 活动结束,使用 dbActCfgID 处理结算,支持结束前维护,结束后启动的情况
+    ipyData = IpyGameDataPY.GetIpyGameData("ActHeroAppear", dbActCfgID)
+    if not ipyData:
+        return
+    templateID = ipyData.GetBillTempID()
+    mailKey = ipyData.GetBillAwardMail()
+    
+    funcName = "ActHeroAppear_%s_%s" % (dbActCfgID, actNum)
+    PlayerBillboard.DoGiveBillboardAwardByActTempID(ShareDefine.Def_BT_ActHeroAppear, funcName, templateID, mailKey, groupValue1=actNum, isClearData=True)
+    return
+
+## -------------------------------------------------------------------------------------------------
+
+def OnPlayerLogin(curPlayer):
+    
+    for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_HeroAppear, {}).values():
+        actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
+        isReset = __CheckPlayerActHeroAppearAction(curPlayer, actNum)
+        # 活动中同步活动信息
+        if not isReset and actInfo.get(ShareDefine.ActKey_State):
+            Sync_ActHeroAppearActionInfo(curPlayer, actNum)
+            Sync_ActHeroAppearPlayerInfo(curPlayer, actNum)
+            PlayerActSign.Sync_ActSignPlayerInfo(curPlayer, ShareDefine.OperationActionName_HeroAppear, actNum)
+    return
+
+def RefreshActHeroAppearActionInfo(actNum):
+    ## 刷新活动
+    playerManager = GameWorld.GetPlayerManager()
+    for index in xrange(playerManager.GetPlayerCount()):
+        curPlayer = playerManager.GetPlayerByIndex(index)
+        if not GameWorld.IsNormalPlayer(curPlayer):
+            continue
+        __CheckPlayerActHeroAppearAction(curPlayer, actNum)
+    return
+
+def __CheckPlayerActHeroAppearAction(curPlayer, actNum):
+    ## 检查玩活动数据信息
+    
+    playerID = curPlayer.GetPlayerID()
+    
+    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_HeroAppear, actNum)
+    actID = actInfo.get(ShareDefine.ActKey_ID, 0)
+    state = actInfo.get(ShareDefine.ActKey_State, 0)
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    
+    playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActHeroAppearID % actNum) # 玩家身上的活动ID
+    
+    # 活动ID 相同的话不处理
+    if actID == playerActID:
+        GameWorld.DebugLog("武将登场活动ID不变,不处理! actNum=%s,cfgID=%s,actID=%s" % (actNum, cfgID, actID), playerID)
+        return
+    lastCfgID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActHeroAppearCfgID % actNum)
+    GameWorld.DebugLog("武将登场活动重置! actNum=%s,cfgID=%s,actID=%s,playerActID=%s,state=%s,lastCfgID=%s" 
+                       % (actNum, cfgID, actID, playerActID, state, lastCfgID), playerID)
+    if lastCfgID:
+        __resetActByCfgID(curPlayer, lastCfgID)
+        
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActHeroAppearCfgID % actNum, cfgID)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActHeroAppearID % actNum, actID)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActHeroAppearStarIndex % actNum, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActHeroAppearStarAward % actNum, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActHeroAppearCallIndex % actNum, 0)
+    
+    if state:
+        Sync_ActHeroAppearActionInfo(curPlayer, actNum)
+        Sync_ActHeroAppearPlayerInfo(curPlayer, actNum)
+        __resetActByCfgID(curPlayer, cfgID)
+        
+    return True
+
+def __resetActByCfgID(curPlayer, cfgID):
+    if not cfgID:
+        return
+    ipyData = IpyGameDataPY.GetIpyGameData("ActHeroAppear", cfgID)
+    if not ipyData:
+        return
+    actNum = ipyData.GetActNum()
+    # 签到
+    PlayerActSign.ResetActSign(curPlayer, ShareDefine.OperationActionName_HeroAppear, actNum)
+    # 寻宝
+    PlayerTreasure.ResetTreasureType(curPlayer, [ipyData.GetActTreasureType()])
+    # 商店
+    shopTypeList = [ipyData.GetGiftShopType(), ipyData.GetExShopType()]
+    FunctionNPCCommon.ResetShopItemBuyCountByShopType(curPlayer, shopTypeList, ipyData.GetExShopRecycleMail())
+    # 充值
+    resetCTGIDList = []
+    resetCTGIDList += ipyData.GetSkinCTGIDList()
+    resetCTGIDList += ipyData.GetGiftCTGIDList()
+    PlayerCoin.DoResetCTGCountByIDList(curPlayer, "ActHeroAppear", resetCTGIDList)
+    return
+
+def GetActNumByTreasureType(curPlayer, treasureType):
+    ## 根据寻宝类型获取活动中的武将登场actNum
+    # @return: 0-非活动中;>0-活动中的actNum
+    for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_HeroAppear, {}).values():
+        if not actInfo.get(ShareDefine.ActKey_State):
+            continue
+        cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+        ipyData = IpyGameDataPY.GetIpyGameData("ActHeroAppear", cfgID)
+        if not ipyData:
+            continue
+        if treasureType != ipyData.GetActTreasureType():
+            continue
+        actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
+        return actNum
+    return 0
+
+def IsActCanTreasureHero(curPlayer, treasureType, heroID, gridNum):
+    ## 是否活动中可产出的武将
+    
+    actOnlyHeroLibList = IpyGameDataPY.GetFuncEvalCfg("HeroAppear", 1)
+    if gridNum not in actOnlyHeroLibList:
+        #GameWorld.DebugLog("非登场武将格子的可直接产出! heroID=%s,gridNum=%s" % (heroID, gridNum))
+        return True
+    #GameWorld.DebugLog("验证可否产出活动武将! heroID=%s,gridNum=%s" % (heroID, gridNum))
+    
+    for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_HeroAppear, {}).values():
+        if not actInfo.get(ShareDefine.ActKey_State):
+            continue
+        cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+        ipyData = IpyGameDataPY.GetIpyGameData("ActHeroAppear", cfgID)
+        if not ipyData:
+            continue
+        if treasureType != ipyData.GetActTreasureType():
+            continue
+        actHeroIDList = ipyData.GetActHeroIDList()        
+        actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
+        callHeroIndex = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActHeroAppearCallIndex % actNum)
+        if not actHeroIDList or len(actHeroIDList) <= callHeroIndex:
+            return False
+        callHeroID = actHeroIDList[callHeroIndex]
+        if heroID != callHeroID:
+            #GameWorld.DebugLog("非选择的登场武将,不可产出! heroID=%s != %s,callHeroIndex=%s,%s" % (heroID, callHeroID, callHeroIndex, actHeroIDList))
+            return False
+        return True
+    return False
+
+#// AA 01 武将登场升星武将选择 #tagCSActHeroAppearStarHeroSelect
+#
+#struct    tagCSActHeroAppearStarHeroSelect
+#{
+#    tagHead        Head;
+#    BYTE        ActNum;        // 活动编号
+#    BYTE        StarHeroIndex;    // 升星计划选择的武将ID索引
+#};
+def OnStarHeroSelect(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    actNum = clientData.ActNum
+    starHeroIndex = clientData.StarHeroIndex
+    
+    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_HeroAppear, actNum)
+    if not actInfo or not actInfo.get(ShareDefine.ActKey_State):
+        GameWorld.DebugLog("该武将登场非活动中: actNum=%s" % actNum, playerID)
+        return
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    ipyData = IpyGameDataPY.GetIpyGameData("ActHeroAppear", cfgID)
+    if not ipyData:
+        return
+    actHeroIDList = ipyData.GetActHeroIDList()
+    if not actHeroIDList or len(actHeroIDList) <= starHeroIndex:
+        GameWorld.DebugLog("武将登场星级计划武将选择索引非法: actNum=%s,cfgID=%s,starHeroIndex=%s,actHeroIDList=%s" 
+                           % (actNum, cfgID, starHeroIndex, actHeroIDList), playerID)
+        return
+    
+    starAward = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActHeroAppearStarAward % actNum)
+    if starAward:
+        GameWorld.DebugLog("武将登场星级计划已经领过奖无法修改星级计划武将: actNum=%s" % actNum, playerID)
+        return
+    
+    starHeroID = actHeroIDList[starHeroIndex]
+    GameWorld.DebugLog("武将登场星级计划武将修改: actNum=%s,cfgID=%s,starHeroIndex=%s,starHeroID=%s,actHeroIDList=%s" 
+                           % (actNum, cfgID, starHeroIndex, starHeroID, actHeroIDList), playerID)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActHeroAppearStarIndex % actNum, starHeroIndex)
+    Sync_ActHeroAppearPlayerInfo(curPlayer, actNum)
+    return
+
+#// AA 02 武将登场招募武将选择 #tagCSActHeroAppearCallHeroSelect
+#
+#struct    tagCSActHeroAppearCallHeroSelect
+#{
+#    tagHead        Head;
+#    BYTE        ActNum;        // 活动编号
+#    BYTE        CallHeroIndex;    // 招募选择的武将ID索引
+#};
+def OnCallHeroSelect(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    actNum = clientData.ActNum
+    callHeroIndex = clientData.CallHeroIndex
+    
+    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_HeroAppear, actNum)
+    if not actInfo or not actInfo.get(ShareDefine.ActKey_State):
+        GameWorld.DebugLog("该武将登场非活动中: actNum=%s" % actNum, playerID)
+        return
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    ipyData = IpyGameDataPY.GetIpyGameData("ActHeroAppear", cfgID)
+    if not ipyData:
+        return
+    actHeroIDList = ipyData.GetActHeroIDList()
+    if not actHeroIDList or len(actHeroIDList) <= callHeroIndex:
+        GameWorld.DebugLog("武将登场招募武将选择索引非法: actNum=%s,cfgID=%s,callHeroIndex=%s,actHeroIDList=%s" 
+                           % (actNum, cfgID, callHeroIndex, actHeroIDList), playerID)
+        return
+    
+    starHeroID = actHeroIDList[callHeroIndex]
+    GameWorld.DebugLog("武将登场招募武将修改: actNum=%s,cfgID=%s,callHeroIndex=%s,starHeroID=%s,actHeroIDList=%s" 
+                           % (actNum, cfgID, callHeroIndex, starHeroID, actHeroIDList), playerID)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActHeroAppearCallIndex % actNum, callHeroIndex)
+    Sync_ActHeroAppearPlayerInfo(curPlayer, actNum)
+    return
+
+def GetHeroAppearStarFreeAward(curPlayer, dataEx):
+    ## 领取升星计划免费奖励
+    actNum = dataEx
+    playerID = curPlayer.GetPlayerID()
+    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_HeroAppear, actNum)
+    if not actInfo or not actInfo.get(ShareDefine.ActKey_State):
+        GameWorld.DebugLog("该武将登场非活动中: actNum=%s" % actNum)
+        return
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    ipyData = IpyGameDataPY.GetIpyGameData("ActHeroAppear", cfgID)
+    if not ipyData:
+        return
+    starGiftTempID = ipyData.GetStarGiftTempID()
+    actHeroIDList = ipyData.GetActHeroIDList()
+    starHeroIndex = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActHeroAppearStarIndex % actNum)
+    if starHeroIndex >= len(actHeroIDList):
+        return
+    starHeroID = actHeroIDList[starHeroIndex]
+    
+    awardIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActHeroAppearStar", starGiftTempID)
+    if not awardIpyDataList:
+        return
+    
+    heroStar = PlayerHero.GetHeroItemStarMax(curPlayer, starHeroID)
+    
+    awardItemList = []
+    updStarAward = starAward = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActHeroAppearStarAward % actNum)
+    for awardIpyData in awardIpyDataList:
+        if heroStar < awardIpyData.GetNeedStar():
+            continue
+        awardIndex = awardIpyData.GetAwardIndex()
+        if starAward&pow(2, awardIndex):
+            continue
+        awardItemList += awardIpyData.GetFreeAwardItemList()
+        updStarAward |= pow(2, awardIndex)
+        
+    GameWorld.DebugLog("武将登场星级计划免费奖励领取! actNum=%s,cfgID=%s,starHeroIndex=%s,starHeroID=%s,heroStar=%s,starAward=%s" 
+                       % (actNum, cfgID, starHeroIndex, starHeroID, heroStar, starAward), playerID)
+    if not awardItemList:
+        GameWorld.DebugLog("没有可领免费奖励!", playerID)
+        return
+    GameWorld.DebugLog("updStarAward=%s,awardItemList=%s" % (updStarAward, awardItemList), playerID)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActHeroAppearStarAward % actNum, updStarAward)
+    ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, event=["HeroAppearStar", False, {}])
+    Sync_ActHeroAppearPlayerInfo(curPlayer, actNum)
+    return
+
+def GetCTGActItemList(curPlayer, ctgID):
+    ## 活动充值ID额外物品列表
+    # @return: [[itemID,count], ...]
+    for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_HeroAppear, {}).values():
+        actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
+        if not actInfo.get(ShareDefine.ActKey_State):
+            continue
+        cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+        ipyData = IpyGameDataPY.GetIpyGameData("ActHeroAppear", cfgID)
+        if not ipyData:
+            continue
+        starGiftTempID = ipyData.GetStarGiftTempID()
+        actHeroIDList = ipyData.GetActHeroIDList()
+        starHeroIndex = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActHeroAppearStarIndex % actNum)
+        if starHeroIndex >= len(actHeroIDList):
+            continue
+        starHeroID = actHeroIDList[starHeroIndex]
+        
+        awardIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActHeroAppearStar", starGiftTempID)
+        if not awardIpyDataList:
+            continue
+        for awardIpyData in awardIpyDataList:
+            if ctgID != awardIpyData.GetStarGiftCTGID():
+                continue
+            heroGiftItemInfo = awardIpyData.GetHeroGiftItemInfo()
+            if str(starHeroID) not in heroGiftItemInfo:
+                return []
+            return heroGiftItemInfo[str(starHeroID)]
+    return []
+
+def Sync_ActHeroAppearPlayerInfo(curPlayer, actNum):
+    clientPack = ChPyNetSendPack.tagSCActHeroAppearPlayerInfo()
+    clientPack.ActNum = actNum
+    clientPack.StarHeroIndex = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActHeroAppearStarIndex % actNum)
+    clientPack.StarFreeAward = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActHeroAppearStarAward % actNum)
+    clientPack.CallHeroIndex = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActHeroAppearCallIndex % actNum)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+def Sync_ActHeroAppearActionInfo(curPlayer, actNum, roundType=0):
+    ## 通知活动信息
+    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_HeroAppear, actNum)
+    if not actInfo or not actInfo.get(ShareDefine.ActKey_State):
+        return
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    ipyData = IpyGameDataPY.GetIpyGameData("ActHeroAppear", cfgID)
+    if not ipyData:
+        return
+    startDateStr, endDateStr = GameWorld.GetOperationActionDateStr(ipyData)
+    clientPack = ChPyNetSendPack.tagSCActHeroAppearInfo()
+    clientPack.ActType = ShareDefine.OperationActTypeDict.get(ShareDefine.OperationActionName_HeroAppear, 0)
+    clientPack.ActNum = actNum
+    clientPack.StartDate = startDateStr
+    clientPack.EndtDate = endDateStr
+    clientPack.CfgID = cfgID
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActLoginNew.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActLoginNew.py
deleted file mode 100644
index 6ebf30d..0000000
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActLoginNew.py
+++ /dev/null
@@ -1,278 +0,0 @@
-#!/usr/bin/python
-# -*- coding: GBK -*-
-#-------------------------------------------------------------------------------
-#
-##@package Player.PlayerActLoginNew
-#
-# @todo:登录活动-新
-# @author hxp
-# @date 2024-06-03
-# @version 1.0
-#
-# 详细描述: 登录活动-新
-#
-#-------------------------------------------------------------------------------
-#"""Version = 2024-06-03 18:00"""
-#-------------------------------------------------------------------------------
-
-import PyGameData
-import PlayerCoin
-import ShareDefine
-import PlayerControl
-import IpyGameDataPY
-#import PlayerZhanling
-import ChPyNetSendPack
-import ItemControler
-import IPY_GameWorld
-import NetPackCommon
-import GameWorld
-import ChConfig
-import time
-
-def OnPlayerLogin(curPlayer):
-    
-    for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_ActLoginNew, {}).values():
-        actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
-        isReset = __CheckPlayerActLoginAction(curPlayer, actNum)
-        # 活动中同步活动信息
-        if not isReset and actInfo.get(ShareDefine.ActKey_State) and curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActLoginNewID % actNum):
-            Sync_ActLoginActionInfo(curPlayer, actNum)
-            Sync_ActLoginPlayerInfo(curPlayer, actNum)
-            
-    return
-
-def OnDay(curPlayer):
-    OnCheckRelateFuncAct(curPlayer)
-    return
-
-def OnCheckRelateFuncAct(curPlayer, openFuncIDList=None):
-    ## 检查关联功能ID开启的活动
-    for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_ActLoginNew, {}).values():
-        if not actInfo.get(ShareDefine.ActKey_State):
-            continue
-        cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
-        ipyData = IpyGameDataPY.GetIpyGameData("ActLoginNew", cfgID)
-        if not ipyData:
-            continue
-        if not hasattr(ipyData, "GetRelateFuncID"):
-            continue
-        relateFuncID = ipyData.GetRelateFuncID()
-        if not relateFuncID:
-            continue
-        if openFuncIDList and relateFuncID not in openFuncIDList:
-            continue
-        actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0)
-        __CheckPlayerActLoginAction(curPlayer, actNum)
-        
-    return
-
-def RefreshActLoginActionInfo(actNum):
-    ## 收到GameServer同步的活动信息,刷新活动信息
-    playerManager = GameWorld.GetPlayerManager()
-    for index in xrange(playerManager.GetPlayerCount()):
-        curPlayer = playerManager.GetPlayerByIndex(index)
-        if not GameWorld.IsNormalPlayer(curPlayer):
-            continue
-        __CheckPlayerActLoginAction(curPlayer, actNum)
-    return
-
-def __CheckPlayerActLoginAction(curPlayer, actNum):
-    ## 检查玩活动数据信息
-    
-    playerID = curPlayer.GetPlayerID()
-    
-    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_ActLoginNew, actNum)
-    actID = actInfo.get(ShareDefine.ActKey_ID, 0)
-    state = actInfo.get(ShareDefine.ActKey_State, 0)
-    
-    playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActLoginNewID % actNum) # 玩家身上的活动ID
-    
-    funcActInfo = GameWorld.GetActRelateFuncInfo(curPlayer, "ActLoginNew", actInfo, playerActID)
-    if funcActInfo:
-        isInAct, actID = funcActInfo
-        if not isInAct:
-            return
-        
-    # 活动ID 相同的话不处理
-    if actID == playerActID:
-        GameWorld.DebugLog("新登录活动ID不变,不处理! actNum=%s,actID=%s" % (actNum, actID), curPlayer.GetPlayerID())
-        return
-    GameWorld.DebugLog("新登录活动重置! actNum=%s,actID=%s,playerActID=%s,state=%s" % (actNum, actID, playerActID, state), playerID)
-    
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActLoginNewID % actNum, actID)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActLoginNewAward % actNum, 0)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActLoginNewAwardEx % actNum, 0)
-    
-    if state:
-        cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
-        ipyData = IpyGameDataPY.GetIpyGameData("ActLoginNew", cfgID)
-        if ipyData:
-            if ipyData.GetAwardExCTGID():
-                PlayerCoin.DoResetCTGCountByIDList(curPlayer, "ActLoginNew", [ipyData.GetAwardExCTGID()])
-            #if ipyData.GetActZhanlingType():
-            #    PlayerZhanling.ResetZhanling(curPlayer, ipyData.GetActZhanlingType())
-        Sync_ActLoginActionInfo(curPlayer, actNum)
-        Sync_ActLoginPlayerInfo(curPlayer, actNum)
-    return True
-
-def OnGetActLoginAward(curPlayer, dayNum, actNum):
-    ## 领取活动奖励
-    
-    isAwardEx = dayNum / 1000
-    dayNum = dayNum % 1000
-    actNum = GameWorld.ToIntDef(actNum)
-    
-    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_ActLoginNew, actNum)
-    if not actInfo:
-        GameWorld.DebugLog("没有该登录活动! actNum=%s" % actNum)
-        return
-    
-    if not actInfo.get(ShareDefine.ActKey_State):
-        GameWorld.DebugLog("非登录活动中! actNum=%s" % actNum)
-        return
-    
-    playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActLoginNewID % actNum)
-    if not playerActID:
-        return
-    
-    curDayNum = GameWorld.GetDiff_Day(int(time.time()), playerActID) + 1
-    if curDayNum < dayNum:
-        GameWorld.DebugLog("未到可领取的登录天,无法领取!  actNum=%s,curDayNum=%s < %s" % (actNum, curDayNum, dayNum))
-        return
-    
-    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
-    ipyData = IpyGameDataPY.GetIpyGameData("ActLoginNew", cfgID)
-    if not ipyData:
-        return
-    templateID = ipyData.GetTemplateID()
-    
-    dayIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActLoginNewAward", templateID)
-    if not dayIpyDataList:
-        return
-    
-    findIpyData = None
-    for dayIpyData in dayIpyDataList:
-        if dayIpyData.GetDayNum() == dayNum:
-            findIpyData = dayIpyData
-            break
-        
-    if not findIpyData:
-        GameWorld.DebugLog("找不到对应登录天奖励! actNum=%s,cfgID=%s,templateID=%s,dayNum=%s" % (actNum, cfgID, templateID, dayNum))
-        return
-    
-    if isAwardEx:
-        awardExCTGID = ipyData.GetAwardExCTGID()
-        if not awardExCTGID:
-            GameWorld.DebugLog("该登录活动没有扩展奖励! actNum=%s,cfgID=%s" % (actNum, cfgID))
-            return
-        if not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CTGGoodsBuyCount % awardExCTGID):
-            GameWorld.DebugLog("该登录活动扩展奖励礼包未购买,无法领取! actNum=%s,cfgID=%s,awardExCTGID=%s" % (actNum, cfgID, awardExCTGID))
-            return
-        stateKey = ChConfig.Def_PDict_ActLoginNewAwardEx
-        awardItemList = findIpyData.GetLoginAwardItemListEx()
-    else:
-        stateKey = ChConfig.Def_PDict_ActLoginNewAward
-        awardItemList = findIpyData.GetLoginAwardItemList()
-        
-    if not awardItemList:
-        return
-    
-    awardRecord = curPlayer.NomalDictGetProperty(stateKey % actNum)
-    if awardRecord & pow(2, dayNum):
-        GameWorld.DebugLog("登录活动该天已领奖! actNum=%s,dayNum=%s,awardRecord=%s" % (actNum, dayNum, awardRecord))
-        return
-    
-    # 判断非当天需补签
-    costMoneyType, costMoneyValue = 0, 0
-    if curDayNum != dayNum and ipyData.GetRepSignCostMoneyInfo():
-        costMoneyType, costMoneyValue = ipyData.GetRepSignCostMoneyInfo()
-        if costMoneyType and costMoneyValue and not PlayerControl.HaveMoney(curPlayer, costMoneyType, costMoneyValue):
-            return
-        
-    if not ItemControler.CheckPackSpaceEnough(curPlayer, awardItemList):
-        return
-    
-    if costMoneyType and costMoneyValue:
-        PlayerControl.PayMoney(curPlayer, costMoneyType, costMoneyValue, "ActLoginNew", {"actNum":actNum, "dayNum":dayNum, "isAwardEx":isAwardEx})
-        
-    updAwardRecord = awardRecord | pow(2, dayNum)
-    PlayerControl.NomalDictSetProperty(curPlayer, stateKey % actNum, updAwardRecord)
-    Sync_ActLoginPlayerInfo(curPlayer, actNum)
-    
-    GameWorld.DebugLog("领取登录活动奖励! actNum=%s,dayNum=%s,isAwardEx=%s,awardItemList=%s,curDayNum=%s" % (actNum, dayNum, isAwardEx, awardItemList, curDayNum))
-    
-    for itemID, itemCount, isAuctionItem in awardItemList:
-        ItemControler.GivePlayerItem(curPlayer, itemID, itemCount, isAuctionItem, [IPY_GameWorld.rptItem], event=["ActLoginNew", False, {}])
-    ItemControler.NotifyGiveAwardInfo(curPlayer, awardItemList, "ActLoginNew")
-    return
-
-def Sync_ActLoginPlayerInfo(curPlayer, actNum):
-    ## 通知活动玩家信息
-    clientPack = ChPyNetSendPack.tagMCActLoginPlayerInfoNew()
-    clientPack.ActNum = actNum
-    clientPack.LoginAward = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActLoginNewAward % actNum)
-    clientPack.LoginAwardEx = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActLoginNewAwardEx % actNum)
-    NetPackCommon.SendFakePack(curPlayer, clientPack)
-    return
-
-def Sync_ActLoginActionInfo(curPlayer, actNum):
-    ## 通知活动信息
-    actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_ActLoginNew, actNum)
-    if not actInfo:
-        return
-    if not actInfo.get(ShareDefine.ActKey_State):
-        return
-    playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActLoginNewID % actNum)
-    if not playerActID:
-        return
-    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
-    ipyData = IpyGameDataPY.GetIpyGameData("ActLoginNew", cfgID)
-    if not ipyData:
-        return
-    moneyType, moneyValue = ipyData.GetRepSignCostMoneyInfo()
-    templateID = ipyData.GetTemplateID()
-    dayIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActLoginNewAward", templateID)
-    if not dayIpyDataList:
-        return
-    
-    if hasattr(ipyData, "GetRelateFuncID") and ipyData.GetRelateFuncID():
-        startDateStr, endDateStr = GameWorld.GetActRelateFuncDate(ipyData, playerActID, True)
-    else:
-        startDateStr, endDateStr = GameWorld.GetOperationActionDateStr(ipyData)
-    actPack = ChPyNetSendPack.tagMCActLoginNew()
-    actPack.Clear()
-    actPack.ActNum = actNum
-    actPack.StartDate = startDateStr
-    actPack.EndtDate = endDateStr
-    actPack.LimitLV = ipyData.GetLVLimit()
-    actPack.RepSignMoneyType = moneyType
-    actPack.RepSignMoneyValue = moneyValue
-    actPack.AwardExCTGID = ipyData.GetAwardExCTGID()
-    
-    actPack.AwardDayList = []
-    for dayIpyData in dayIpyDataList:
-        dayInfo = ChPyNetSendPack.tagMCActLoginNewDay()
-        dayInfo.DayNum = dayIpyData.GetDayNum()
-        dayInfo.AwardItemList = []
-        for itemID, itemCount, isAuctionItem in dayIpyData.GetLoginAwardItemList():
-            itemInfo = ChPyNetSendPack.tagMCActLoginNewItem()
-            itemInfo.ItemID = itemID
-            itemInfo.ItemCount = itemCount
-            itemInfo.IsBind = isAuctionItem
-            dayInfo.AwardItemList.append(itemInfo)
-        dayInfo.Count = len(dayInfo.AwardItemList)
-        
-        dayInfo.AwardItemListEx = []
-        for itemID, itemCount, isAuctionItem in dayIpyData.GetLoginAwardItemListEx():
-            itemInfo = ChPyNetSendPack.tagMCActLoginNewItem()
-            itemInfo.ItemID = itemID
-            itemInfo.ItemCount = itemCount
-            itemInfo.IsBind = isAuctionItem
-            dayInfo.AwardItemListEx.append(itemInfo)
-        dayInfo.CountEx = len(dayInfo.AwardItemListEx)
-        
-        actPack.AwardDayList.append(dayInfo)
-    actPack.DayCount = len(actPack.AwardDayList)
-    NetPackCommon.SendFakePack(curPlayer, actPack)
-    return
-
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActSign.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActSign.py
new file mode 100644
index 0000000..d3349d5
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActSign.py
@@ -0,0 +1,98 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerActSign
+#
+# @todo:通用的活动登录签到
+# @author hxp
+# @date 2026-02-26
+# @version 1.0
+#
+# 详细描述: 通用的活动登录签到
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2026-02-26 16:00"""
+#-------------------------------------------------------------------------------
+
+import ShareDefine
+import PlayerControl
+import IpyGameDataPY
+import ChPyNetSendPack
+import ItemControler
+import NetPackCommon
+import GameWorld
+import ChConfig
+
+def ResetActSign(curPlayer, actName, actNum):
+    if actName not in ShareDefine.OperationActTypeDict:
+        return
+    actType = ShareDefine.OperationActTypeDict[actName]
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActSignAward % (actType, actNum), 0)
+    GameWorld.DebugLog("重置活动签到: %s,actType=%s,actNum=%s" % (actName, actType, actNum), curPlayer.GetPlayerID())
+    Sync_ActSignPlayerInfo(curPlayer, actName, actNum)
+    return
+
+def OnGetActSignAward(curPlayer, dataEx, dataExStr):
+    ## 领取活动签到奖励
+    actType = GameWorld.ToIntDef(dataExStr)
+    actNum = dataEx
+    
+    playerID = curPlayer.GetPlayerID()
+    actName = ""
+    for aName, aType in ShareDefine.OperationActTypeDict.items():
+        if aType == actType:
+            actName = aName
+            break
+        
+    actInfo = GameWorld.GetActInfo(actName, actNum)
+    if not actInfo or not actInfo.get(ShareDefine.ActKey_State):
+        GameWorld.DebugLog("活动签到非活动中: actType=%s,actNum=%s,actName=%s" % (actType, actNum, actName), playerID)
+        return
+    cfgID = actInfo.get(ShareDefine.ActKey_CfgID)
+    dayIndex = actInfo.get(ShareDefine.ActKey_DayIndex)
+    ipyData = IpyGameDataPY.GetIpyGameData(actName, cfgID)
+    if not ipyData:
+        return
+    if not hasattr(ipyData, "GetSignTempID"):
+        GameWorld.DebugLog("活动无签到: actType=%s,actNum=%s,actName=%s" % (actType, actNum, actName), playerID)
+        return
+    signTempID = ipyData.GetSignTempID()
+    signIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActSignAward", signTempID)
+    if not signIpyDataList:
+        return
+    
+    awardItemList = []
+    updAwardRecord = awardRecord = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActSignAward % (actType, actNum))
+    for dayIpyData in signIpyDataList:
+        dayNum = dayIpyData.GetDayNum()
+        if (dayIndex + 1) < dayNum:
+            break
+        if awardRecord & pow(2, dayNum):
+            #GameWorld.DebugLog("该活动签到天已领取! dayNum=%s" % dayNum)
+            continue
+        awardItemList += dayIpyData.GetSignAwardItemList()
+        updAwardRecord |= pow(2, dayNum)
+        
+    if not awardItemList:
+        GameWorld.DebugLog("没有可领取的活动签到奖励! actType=%s,actNum=%s,actName=%s,dayIndex=%s,awardRecord=%s" 
+                           % (actType, actNum, actName, dayIndex, awardRecord), playerID)
+        return
+    
+    GameWorld.DebugLog("领取活动签到奖励! actType=%s,actNum=%s,actName=%s,dayIndex=%s,awardRecord=%s,updAwardRecord=%s,%s" 
+                           % (actType, actNum, actName, dayIndex, awardRecord, updAwardRecord, awardItemList), playerID)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActSignAward % (actType, actNum), updAwardRecord)
+    Sync_ActSignPlayerInfo(curPlayer, actName, actNum)
+    ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, event=["ActSign", False, {}])
+    return
+
+def Sync_ActSignPlayerInfo(curPlayer, actName, actNum):
+    if actName not in ShareDefine.OperationActTypeDict:
+        return
+    actType = ShareDefine.OperationActTypeDict[actName]
+    clientPack = ChPyNetSendPack.tagSCActSignPlayerInfo()
+    clientPack.ActType = actType
+    clientPack.ActNum = actNum
+    clientPack.SignAward = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActSignAward % (actType, actNum))
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py
index 5c3416a..72fdac1 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py
@@ -106,7 +106,7 @@
 #    
 #    return True
 
-def UpdatePlayerBillboard(curPlayer, bType, cmpValue, cmpValue2=0, cmpValue3=0, autoSort=False, **kwargs):
+def UpdatePlayerBillboard(curPlayer, bType, cmpValue, cmpValue2=0, cmpValue3=0, autoSort=False, groupValue1=0, **kwargs):
     ## 更新玩家排行榜
     
     #if not cmpValue and not cmpValue2 and not cmpValue3:
@@ -123,7 +123,6 @@
     kwargs["value5"] = curPlayer.GetModelMark()
     kwargs["value6"] = curPlayer.GetEquipShowSwitch()
     
-    groupValue1 = 0
     UpdateBillboard(bType, groupValue1, playerID, playerName, playerOpInfo, playerJob, value1, value2, 
                     cmpValue, cmpValue2, cmpValue3, autoSort=autoSort, **kwargs)
     return
@@ -389,9 +388,37 @@
     clientPack.ViewIDDataCnt = len(clientPack.ViewIDDataList)
     return clientPack
 
-def DoGiveBillboardAwardByMail(billboardType, funcName, billboardAwardDict, mailKey):
+def SetOrderRuleListByActTempID(billboardType, templateID, groupValue1=0, groupValue2=0):
+    ## 根据活动榜单模版更新排名规则
+    orderRuleList = []
+    orderIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActBillboardAward", templateID)
+    if orderIpyDataList:
+        for ipyData in orderIpyDataList:
+            orderRuleList.append([ipyData.GetRankB(), ipyData.GetNeedValue()])
+            
+    billboardMgr = DBDataMgr.GetBillboardMgr()
+    billBoard = billboardMgr.GetBillboard(billboardType, groupValue1, groupValue2)
+    billBoard.SetOrderRuleList(orderRuleList)
+    return
+
+def DoGiveBillboardAwardByActTempID(billboardType, funcName, templateID, mailKey, groupValue1=0, groupValue2=0, isClearData=False):
+    ## 根据活动榜单模版结算排名奖励,邮件发放
+    # @param funcName: 自定义的功能名称
+    billboardAwardDict = {}
+    orderIpyDataList = IpyGameDataPY.GetIpyGameDataList("ActBillboardAward", templateID)
+    if orderIpyDataList:
+        for ipyData in orderIpyDataList:
+            billboardAwardDict[str(ipyData.GetRankB())] = ipyData.GetAwardItemList()
+    DoGiveBillboardAwardByMail(billboardType, funcName, billboardAwardDict, mailKey, groupValue1, groupValue2, isClearData)
+    return
+
+def DoGiveBillboardAwardByMail(billboardType, funcName, billboardAwardDict, mailKey, groupValue1=0, groupValue2=0, isClearData=False):
     ## 结算排行奖励邮件发放
-    GameWorld.Log("=== %s结算排行奖励! === " % (funcName))
+    # @param funcName: 自定义的功能名称
+    # @param billboardAwardDict: {"名次":[[itemID,itemCnt], ...], ...}
+    # @param mailKey: 邮件模版key
+    
+    GameWorld.Log("----- %s 结算排行奖励! -----" % (funcName))
     if not billboardAwardDict:
         return
     orderList = [int(orderStr) for orderStr in billboardAwardDict.keys()]
@@ -399,10 +426,11 @@
     GameWorld.Log("    奖励名次列表: %s" % orderList)
     
     billboardMgr = DBDataMgr.GetBillboardMgr()
-    billBoard = billboardMgr.GetBillboard(billboardType)
+    billBoard = billboardMgr.GetBillboard(billboardType, groupValue1, groupValue2)
     if not billBoard:
         return
     billBoard.SortDelayDo()
+    idOrderDict = billBoard.GetIDOrderDict()
     
     awardOrder = orderList[0]
     orderPlayerIDDict = {}
@@ -412,15 +440,19 @@
         billBoardData = billBoard.At(index)
         if not billBoardData:
             continue
-        order = index + 1
+        playerID = billBoardData.GetID()
+        order = idOrderDict.get(playerID, index + 1)
         
-        if order > awardOrder:
+        endAward = False # 发奖是否结束
+        while order > awardOrder:
             nextOrderIndex = orderList.index(awardOrder) + 1
             if nextOrderIndex >= len(orderList):
+                endAward = True
                 break
             awardOrder = orderList[nextOrderIndex]
-            
-        playerID = billBoardData.GetID()
+        if endAward:
+            break
+        
         if playerID < ShareDefine.RealPlayerIDStart:
             # 非真人不处理
             continue
@@ -432,5 +464,7 @@
         PlayerMail.SendMailByKey(mailKey, playerID, awardList, paramList)
         
     GameWorld.Log("    奖励玩家名次信息: %s" % orderPlayerIDDict)
-    GameWorld.Log("===================================================")
+    if isClearData:
+        billBoard.ClearData("Award")
+    GameWorld.Log("---------------------------------------------------")
     return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCoin.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCoin.py
index db22045..a3ab2ee 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCoin.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerCoin.py
@@ -45,6 +45,7 @@
 import PlayerActTotalRecharge
 import PlayerActManyDayRecharge
 import PlayerActSingleRecharge
+import PlayerActHeroAppear
 import PlayerGoldInvest
 import PlayerZhanling
 import PlayerGoldRush
@@ -561,6 +562,7 @@
     giveItemList = []
     giveItemList += GetCTGGiveItemList(ipyData)
     giveItemList += selectItemList
+    giveItemList += PlayerActHeroAppear.GetCTGActItemList(curPlayer, recordID) # 武将登场
     
     #payType = ipyData.GetPayType()
     moneyType = ipyData.GetMoneyType() # 获得货币类型
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 87076a8..d0181ea 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -37,7 +37,6 @@
 import PlayerGoldInvest
 import PlayerActTask
 import PlayerActBuyCountGift
-import PlayerActLoginNew
 import PlayerOfflineSupport
 import PlayerTreasure
 import PlayerZhanling
@@ -311,8 +310,6 @@
     FBCommon.FBOnDay(curPlayer, onEventType)
     #任务活动
     PlayerActTask.OnDay(curPlayer)
-    #登录活动
-    PlayerActLoginNew.OnDay(curPlayer)
     #购买次数礼包
     PlayerActBuyCountGift.OnDay(curPlayer, onEventType)
     return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerHero.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerHero.py
index aa0880c..fa1abbe 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerHero.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerHero.py
@@ -597,6 +597,19 @@
         singleItem.AddUserAttr(ShareDefine.Def_IudetHeroTalentIDLV, lvList[index])
     return
 
+def GetHeroItemStarMax(curPlayer, heroID):
+    ## 获取某个武将ID当前最大星级
+    starMax = 0
+    curPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptHero)
+    for index in range(curPack.GetCount()):
+        heroItem = curPack.GetAt(index)
+        if not heroItem or heroItem.IsEmpty():
+            continue
+        if heroID != heroItem.GetItemTypeID():
+            continue
+        starMax = max(heroItem.GetUserAttr(ShareDefine.Def_IudetHeroStar), starMax)
+    return starMax
+
 def GetHeroStarTotal(curPlayer):
     ## 武将总星级
     totalStar = 0
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTreasure.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTreasure.py
index b710702..81e52da 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTreasure.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTreasure.py
@@ -24,6 +24,7 @@
 import ItemControler
 import NetPackCommon
 import PlayerActLunhuidian
+import PlayerActHeroAppear
 import PlayerActivity
 import PlayerSuccess
 import PlayerGoldInvest
@@ -34,6 +35,9 @@
 import PlayerHero
 import PyGameData
 import PlayerTask
+import PlayerMail
+import DBDataMgr
+import ChPlayer
 import ChConfig
 
 import random
@@ -61,6 +65,9 @@
 #武将招募的所有类型
 TreasureType_HeroCallList = [TreasureType_HeroComm, TreasureType_HeroHigh, TreasureType_HeroScore]
 
+#活动寻宝类型
+ActType_HeroAppear = 1 # 武将登场
+
 def OnTreasureLogin(curPlayer):
     Sync_TreasureInfo(curPlayer)
     return
@@ -72,11 +79,13 @@
         ipyData = ipyDataMgr.GetTreasureSetByIndex(i)
         treasureType = ipyData.GetTreasureType()
         if not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCountToday % (treasureType)) and \
-            not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureFreeCount % (treasureType)):
+            not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureFreeCount % (treasureType)) and \
+            not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCountTodayGold % (treasureType)):
             continue
         syncTypeList.append(treasureType)
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCountToday % (treasureType), 0)
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureFreeCount % (treasureType), 0)
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCountTodayGold % (treasureType), 0)
         
         # 每日心愿重置
         wishLibSelect = ipyData.GetWishLibSelect()
@@ -114,6 +123,7 @@
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCount % (treasureType), 0)
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCountEx % (treasureType), 0)
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCountToday % (treasureType), 0)
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCountTodayGold % (treasureType), 0)
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureLuck % (treasureType), 0)
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCntAward % (treasureType), 0)
         
@@ -124,10 +134,10 @@
     Sync_TreasureInfo(curPlayer, treasureTypeList)
     return
 
-def IsActTreasureType(curPlayer, treasureType):
+def IsActTreasureType(curPlayer, treasureType, actType):
     ## 是否活动中的寻宝类型
-    #if PlayerActYunshi.IsActTreasureType(curPlayer, treasureType):
-    #    return True
+    if actType == ActType_HeroAppear:
+        return PlayerActHeroAppear.GetActNumByTreasureType(curPlayer, treasureType) > 0
     return False
 
 #// A5 69 寻宝心愿物品选择 #tagCSTreasureWishSelect
@@ -258,9 +268,10 @@
     setIpyData = IpyGameDataPY.GetIpyGameData("TreasureSet", treasureType)
     if not setIpyData:
         return
-    if setIpyData.GetIsActType():
-        if not IsActTreasureType(curPlayer, treasureType):
-            GameWorld.ErrLog("该寻宝类型非活动中,无法寻宝! treasureType=%s" % (treasureType), playerID)
+    actType = setIpyData.GetActType()
+    if actType:
+        if not IsActTreasureType(curPlayer, treasureType, actType):
+            GameWorld.ErrLog("该寻宝类型非活动中,无法寻宝! treasureType=%s,actType=%s" % (treasureType, actType), playerID)
             return
     treasureCountList = setIpyData.GetTreasureCountList() # 寻宝获得个数列表
     if not treasureCountList:
@@ -284,12 +295,15 @@
                            % (treasureCount, curTreasureCountToday, updTreasureCountToday, dailyMaxCount), playerID)
         return
     
-    packType = setIpyData.GetPackType()
-    if setIpyData.GetCheckPack():
-        if not ItemCommon.CheckPackHasSpace(curPlayer, packType, True):
-            GameWorld.DebugLog("对应寻宝背包没有空格子!packType=%s" % packType, playerID)
+    checkPackList = setIpyData.GetCheckPackList()
+    for checkPackType in checkPackList:
+        if not ItemCommon.CheckPackHasSpace(curPlayer, checkPackType, True):
+            GameWorld.DebugLog("对应寻宝背包没有空格子! checkPackType=%s" % checkPackType, playerID)
             return
         
+    curTreasureCountTodayGold = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCountTodayGold % (treasureType)) # 今日元宝已寻宝次数
+    updTreasureCountTodayGold = curTreasureCountTodayGold
+    
     # 免费次数
     if costType == CostType_DayFree:
         dailyFreeCount = setIpyData.GetDailyFreeCount()
@@ -341,6 +355,12 @@
         
     # 仙玉寻宝
     else:
+        dailyMaxCountMoney = setIpyData.GetDailyMaxCountMoney()
+        updTreasureCountTodayGold = curTreasureCountTodayGold + treasureCount
+        if dailyMaxCountMoney and updTreasureCountTodayGold > dailyMaxCountMoney:
+            GameWorld.DebugLog("寻宝后将超过每日最大消耗货币次数,无法寻宝! treasureCount(%s) + curTreasureCountTodayGold(%s) = %s > %s" 
+                               % (treasureCount, curTreasureCountTodayGold, updTreasureCountTodayGold, dailyMaxCountMoney), playerID)
+            return
         costGoldList = setIpyData.GetCostMoneyList() # 消耗货币列表
         costGoldType = setIpyData.GetCostMoneyType() # 消耗货币类型
         if not costGoldType or not costGoldList or treasureIndex >= len(costGoldList):
@@ -380,6 +400,7 @@
     ensureRateList = ipyData.GetGridItemRateList2()
     GameWorld.DebugLog("beSureCountDict=%s" % beSureCountDict, playerID)
     GameWorld.DebugLog("ensureCount=%s, %s" % (ensureCount, ensureRateList), playerID)
+    recordGridNumList = setIpyData.GetRecordGridNumList() # 需要记录产出的格子
     notifyGridNumList = setIpyData.GetNotifyGridNumList() # 额外需要广播的格子,幸运必出、次数必出可不配置
     notifyKeyDict = setIpyData.GetNotifyKeyDict()
     gridNumMaxLimitInfo = setIpyData.GetGridNumMaxLimitInfo() # {"格子":最大可产出次数, ...}
@@ -568,9 +589,9 @@
     randItemIDDict = IpyGameDataPY.GetFuncEvalCfg("TreasureSet", 2)
     
     for gridNum in getGridResult:
-        gridNum = str(gridNum)
-        if gridNum in gridItemInfoDict:
-            itemID, itemCount = gridItemInfoDict[gridNum]
+        gridNumStr = str(gridNum)
+        if gridNumStr in gridItemInfoDict:
+            itemID, itemCount = gridItemInfoDict[gridNumStr]
             itemID = GetJobItem(job, itemID, jobItemList)
             if not itemID:
                 GameWorld.ErrLog("寻宝格子物品ID异常!treasureType=%s,gridNum=%s" % (treasureType, gridNum), playerID)
@@ -581,7 +602,7 @@
                 canRandItemList = []
                 randItemIDList = randItemIDDict[itemID]
                 for randItemID in randItemIDList:
-                    if not __checkItemCanTreasure(curPlayer, treasureType, randItemID):
+                    if not __checkItemCanTreasure(curPlayer, treasureType, randItemID, actType, gridNum):
                         continue
                     canRandItemList.append(randItemID)
                 if not canRandItemList:
@@ -590,12 +611,11 @@
                     return
                 itemID = random.choice(canRandItemList)
         # 根据物品库来随机
-        elif gridNum in gridLibInfoDict:
-            libID = gridLibInfoDict[gridNum]
+        elif gridNumStr in gridLibInfoDict:
+            libID = gridLibInfoDict[gridNumStr]
             libItemList = IpyGameDataPY.GetIpyGameDataList("TreasureItemLib", libID)
             if not libItemList:
                 return
-            
             wishWeightList = [] # 心愿物品权重
             itemWeightList = []
             for libItem in libItemList:
@@ -603,7 +623,7 @@
                 itemWeight, itemID, itemCount = libItem.GetItemWeight(), libItem.GetItemID(), libItem.GetItemCount()
                 if not itemWeight:
                     continue
-                if not __checkItemCanTreasure(curPlayer, treasureType, itemID):
+                if not __checkItemCanTreasure(curPlayer, treasureType, itemID, actType, gridNum):
                     continue
                 itemWeightList.append([itemWeight, [itemID, itemCount]])
                 
@@ -638,7 +658,7 @@
             return
         
         isTrans = 0 # 是否转化
-        treasureResult.append([gridNum, itemID, itemCount, isTrans])
+        treasureResult.append([gridNumStr, itemID, itemCount, isTrans])
         
     # 扣消耗
     if costType == CostType_DayFree:
@@ -660,6 +680,7 @@
     # 加数据
     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCountToday % (treasureType), updTreasureCountToday)
     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCount % (treasureType), updTreasureCount)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCountTodayGold % (treasureType), updTreasureCountTodayGold)
     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureLuck % (treasureType), updLuck)
     for gridNum, updCount in gridNumCountInfo.items():
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureGridCnt % (treasureType, gridNum), updCount)
@@ -694,6 +715,7 @@
                 
     addScoreType = setIpyData.GetAwardMoneyType() # 额外奖励货币类型
     addScore = setIpyData.GetAwardMoneyValue() # 单次奖励货币数
+    awardItemInfo = setIpyData.GetAwardItemInfo() # 单次额外奖励道具,物品ID|个数
     if addScoreType and addScore:
         PlayerControl.GiveMoney(curPlayer, addScoreType, addScore * treasureCount)
         
@@ -707,18 +729,24 @@
         
     PlayerActLunhuidian.AddLunhuidianValue(curPlayer, PlayerActLunhuidian.AwardType_Treasure, treasureType, treasureCount)
     
+    if actType == ActType_HeroAppear:
+        actNum = PlayerActHeroAppear.GetActNumByTreasureType(curPlayer, treasureType)
+        if actNum:
+            PlayerBillboard.UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_ActHeroAppear, updTreasureCount, groupValue1=actNum)
+            
     # 给物品
     mailItemList = []
     itemControl = ItemControler.PlayerItemControler(curPlayer)
     for tResult in treasureResult:
-        gridNum, itemID, itemCount = tResult[:3]
+        gridNumStr, itemID, itemCount = tResult[:3]
+        gridNum = int(gridNumStr)
         PyGameData.g_transItemSign = 0
         itemObj = ItemControler.GetOutPutItemObj(itemID, itemCount, isBind, curPlayer=curPlayer)
         mailItemDict = ItemCommon.GetMailItemDict(itemObj)
         
-        if int(gridNum) in notifyGridNumList and notifyKeyDict:
-            notifyKey = notifyKeyDict.get(int(gridNum), notifyKeyDict.get(0, ""))
-            if treasureType in TreasureType_HeroCallList:
+        if gridNum in notifyGridNumList and notifyKeyDict:
+            notifyKey = notifyKeyDict.get(gridNum, notifyKeyDict.get(0, ""))
+            if itemObj.GetType() == ChConfig.Def_ItemType_Hero:
                 if PlayerHero.GetHeroActivite(curPlayer, itemID):
                     notifyKey = ""
                     GameWorld.DebugLog("招募武将非首次获得的不广播了! itemID=%s" % itemID, playerID)
@@ -730,6 +758,7 @@
             elif notifyKey:
                 PlayerControl.WorldNotify(0, notifyKey, [curPlayer.GetPlayerName(), itemID, itemObj.GetUserData(), itemCount])
             
+        packType = ChConfig.GetItemPackType(itemObj)
         if mailItemList or not itemControl.PutInItem(packType, itemObj, event=[ChConfig.ItemGive_Treasure, False, {}]):
             mailItemList.append(mailItemDict)
             itemObj.Clear()
@@ -738,8 +767,33 @@
         if PyGameData.g_transItemSign:
             tResult[3] = 1 # 有转化物品时设置转化标记
             
+        # 记录产出
+        if gridNum in recordGridNumList:
+            # 可扩展是否跨服类型的寻宝,需要存储到跨服服务器
+            maxCount = 50 # 最多记录条数
+            recTypeIDMgr = DBDataMgr.GetGameRecMgr().GetRecTypeIDMgr(ShareDefine.Def_GameRecType_Treasure, treasureType)
+            recData = recTypeIDMgr.AddRecData(maxCount)
+            recData.SetValue1(itemID)
+            recData.SetValue2(itemCount)
+            recData.SetValue3(playerID)
+            recData.SetValue4(curPlayer.GetServerID())
+            recData.GetUserDict().update({"Name":curPlayer.GetPlayerName()})
+            ChPlayer.SyncGameRecInfo(curPlayer, [recData]) # 主动同步差异,前端每次登录首次开启界面主动查询一次,并根据Time值自行排序
+            
+    # 额外赠送物品
+    addItemID, addItemCount = 0, 0
+    if awardItemInfo and len(awardItemInfo) >= 2:
+        addItemID, addItemCount = awardItemInfo[:2]
+        addItemCount *= treasureCount
+        itemObj = ItemControler.GetOutPutItemObj(addItemID, addItemCount, isBind, curPlayer=curPlayer)
+        if itemObj:
+            packType = ChConfig.GetItemPackType(itemObj)
+            if mailItemList or not itemControl.PutInItem(packType, itemObj, event=[ChConfig.ItemGive_Treasure, False, {}]):
+                mailItemList.append(ItemCommon.GetMailItemDict(itemObj))
+                itemObj.Clear()
+                
     if mailItemList:
-        PlayerControl.SendMailByKey("HappyXBUnEnough", [playerID], mailItemList)
+        PlayerMail.SendMailByKey("", playerID, mailItemList)
         
     GameWorld.DebugLog("寻宝成功: treasureType=%s,updTreasureCount=%s(%s),updLuck=%s,addScoreType=%s,addScore=%s,gridNumCountInfo=%s,treasureCountEx=%s" 
                        % (treasureType, updTreasureCount, updTreasureCountToday, updLuck, addScoreType, addScore, gridNumCountInfo, treasureCountEx), playerID)
@@ -754,6 +808,8 @@
     sendPack.CostType = costType
     sendPack.AddMoneyType = addScoreType
     sendPack.AddMoneyValue = addScore
+    sendPack.AddItemID = addItemID
+    sendPack.AddItemCount = addItemCount
     sendPack.AddTreasureLuck = addLuck
     sendPack.TreasureResult = str(treasureResult)
     sendPack.TreasureResultLen = len(sendPack.TreasureResult)
@@ -825,21 +881,36 @@
     lastLuck = luckyValueList[-1]
     return lastLuck, luckyItemRateDict[lastLuck]
 
-def __checkItemCanTreasure(curPlayer, treasureType, itemID):
+def __checkItemCanTreasure(curPlayer, treasureType, itemID, actType, gridNum):
     ## 检查物品ID是否可寻宝产出
     itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
     if not itemData:
         return
     
     playerID = curPlayer.GetPlayerID()
-    if itemData.GetType() == ChConfig.Def_ItemType_Hero:
-        heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", itemID)
-        if not heroIpyData:
+    itemType = itemData.GetType()
+    heroID = 0
+    if itemType == ChConfig.Def_ItemType_Hero:
+        heroID = itemID
+    elif itemType == ChConfig.Def_ItemType_HeroPiece:
+        heroID = itemData.GetEffectByIndex(0).GetEffectValue(0)
+        if not heroID:
+            GameWorld.DebugLog("武将碎片效果1A值未配置对应的武将ID! itemID=%s" % itemID, playerID)
             return
-        if heroIpyData.GetRecruitBySelf() and not PlayerHero.GetHeroActivite(curPlayer, itemID):
-            GameWorld.DebugLog("武将未激活不产出! itemID=%s" % itemID, playerID)
+    if heroID:
+        heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
+        if not heroIpyData:
+            GameWorld.DebugLog("不存在该武将不产出! itemID=%s,heroID=%s" % (itemID, heroID), playerID)
+            return
+        if heroIpyData.GetRecruitBySelf() and not PlayerHero.GetHeroActivite(curPlayer, heroID):
+            GameWorld.DebugLog("武将未激活不产出! itemID=%s,heroID=%s" % (itemID, heroID), playerID)
             return
         
+        # 武将登场
+        if actType == ActType_HeroAppear:
+            if not PlayerActHeroAppear.IsActCanTreasureHero(curPlayer, treasureType, heroID, gridNum):
+                return
+            
     return True
 
 def GetRemoveLimitGridRateList(srcGridNumRateList, gridNumCountInfo, gridNumMaxLimitInfo):
@@ -943,8 +1014,9 @@
         setIpyData = IpyGameDataPY.GetIpyGameData("TreasureSet", tType)
         if not setIpyData:
             continue
-        if setIpyData.GetIsActType():
-            if not IsActTreasureType(curPlayer, tType):
+        actType = setIpyData.GetActType()
+        if actType:
+            if not IsActTreasureType(curPlayer, tType, actType):
                 continue
         gridNumMaxLimitInfo = setIpyData.GetGridNumMaxLimitInfo()
         tTypeInfo = ChPyNetSendPack.tagMCTreasureTypeInfo()
@@ -953,6 +1025,7 @@
         tTypeInfo.LuckValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureLuck % (tType))
         tTypeInfo.TreasureCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCount % (tType))
         tTypeInfo.TreasureCountToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCountToday % (tType))
+        tTypeInfo.TreasureCountTodayGold = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCountTodayGold % (tType))
         tTypeInfo.FreeCountToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureFreeCount % (tType))
         tTypeInfo.TreasureCntAward = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCntAward % (tType))
         for gridNumStr in gridNumMaxLimitInfo.keys():
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
index ddc2529..c955848 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -47,6 +47,7 @@
 Def_FamilyTransDataTime = 'FamilyTransDataTime' # 本服公会首次跨服互通数据开始传输时间戳,不为0代表传输数据中
 Def_OSAAwardState = 'OSAAwardState' #开服冲榜活动结算状态
 Def_OperationActID = 'OperationActID_%s_%s' # 运营活动ID的标记,参数(运营活动名, actNum)
+Def_OperationActCfgID = 'OperationActCfgID_%s_%s' # 运营活动CfgID的标记,参数(运营活动名, actNum)
 
 #---奇迹, 职业枚举定义---
 (
@@ -211,35 +212,24 @@
 
 #运营活动表名定义
 OperationActionName_Lunhuidian = "ActLunhuidian" # 轮回殿活动
+OperationActionName_HeroAppear = "ActHeroAppear" # 武将登场活动
 
 #所有的运营活动列表,默认都支持多活动分组编号的活动名
-OperationActionNameList = [OperationActionName_Lunhuidian]
+OperationActionNameList = [OperationActionName_Lunhuidian, OperationActionName_HeroAppear]
+
+#活动对应活动类型,每种活动如有需要可以设置对应的唯一类型,可与ActNum组合成唯一的记录key  {ActionName:ActType, ...}
+#一般用于有需要做记录的通用功能,如签到等
+OperationActTypeDict = {OperationActionName_HeroAppear:1,
+                        }
 
 OperationActionName_TotalRecharge = "ActTotalRecharge" # 累计充值活动
 OperationActionName_CollectWords = "ActCollectWords" # 集字活动
 OperationActionName_ManyDayRecharge = "ActManyDayRecharge" # 多日连充活动
 OperationActionName_SingleRecharge = "ActSingleRecharge" # 单笔累充活动
 OperationActionName_BuyOne = "ActBuyOne" # 买一送多活动
-OperationActionName_ActLoginNew = "ActLoginNew" # 登录活动-新
 OperationActionName_ActTask = "ActTask" # 活动任务
 OperationActionName_BuyCountGift = "ActBuyCountGift" # 购买次数礼包活动
 OperationActionName_FamilyCTGAssist = "ActFamilyCTGAssist" # 仙盟充值协助
-
-##所有的运营活动列表,含节日活动
-#OperationActionNameList = [
-#                           OperationActionName_TotalRecharge,
-#                           OperationActionName_SingleRecharge,
-#                           OperationActionName_CollectWords, OperationActionName_ManyDayRecharge,
-#                           OperationActionName_BuyOne,
-#                           OperationActionName_ActLoginNew, OperationActionName_ActTask,
-#                           OperationActionName_BuyCountGift, OperationActionName_FamilyCTGAssist,
-#                           OperationActionName_Lunhuidian,
-#                           ]
-##需要记录开启活动时的世界等级的运营活动
-#NeedWorldLVOperationActNameList = [OperationActionName_TotalRecharge,
-#                                   OperationActionName_CollectWords,
-#                                   OperationActionName_ManyDayRecharge, OperationActionName_SingleRecharge,
-#                                   ]
 
 #跨服运营活动表名定义
 CrossActName_Lianqi = "CrossActLianqi" # 炼器 - 跨服
@@ -335,7 +325,8 @@
 Def_BT_OSA_MainLevel,    # 开服关卡榜 3
 Def_BT_OSA_HeroCall,    # 开服招募榜 4
 Def_BT_Dingjunge,    # 定军阁过关榜 5
-) = range(0, 6) 
+Def_BT_ActHeroAppear,    # 武将登场招募榜 6
+) = range(0, 7) 
 
 ''' 跨服排行榜类型, 从 150 开始,最大条数在功能配置表 CrossBillboardSet 配置,没配默认100
 与本服榜单存储的是不一样的数据库表格,理论上类型可以和本服榜单类型重复,为了做下区分防误导,跨服榜单从 150 开始
@@ -349,7 +340,9 @@
 BillboardTypeAllList = BillboardTypeList + CrossBillboardTypeList
 
 BillboardNameDict = {Def_BT_MainLevel:"主线过关榜", Def_BT_Arena:"演武场积分周榜", Def_BT_Tianzi:"天子考验伤害榜", 
-                     Def_BT_OSA_MainLevel:"开服关卡榜", Def_BT_OSA_HeroCall:"开服招募榜", Def_BT_Dingjunge:"定军阁过关榜"}
+                     Def_BT_OSA_MainLevel:"开服关卡榜", Def_BT_OSA_HeroCall:"开服招募榜", Def_BT_Dingjunge:"定军阁过关榜", 
+                     Def_BT_ActHeroAppear:"武将登场招募榜(分组值1-ActNum)"
+                     }
 
 #仙盟榜单类型
 FamilyBillboardList = []
@@ -784,7 +777,8 @@
                        Def_GameRecType_ArenaRecord, # 演武场玩家挑战记录,playerID 308
                        Def_GameRecType_BatPreset, # 战斗方案预设额外存储信息,playerID 309
                        Def_GameRecType_Setting, # 前端自定义存储的设置内容,playerID 310
-                       ) = range(300, 1 + 310)
+                       Def_GameRecType_Treasure, # 寻宝记录,treasureType 311
+                       ) = range(300, 1 + 311)
 #通用信息记录新 - 字典key配置,如果有配置,则可额外按对应记录Value值存储字典,方便快速取值,可配置Value编号 1~8,配空默认 Value1
 Def_GameRecValueKeyDict = {
                            Def_GameRecType_Xiangong:[1],

--
Gitblit v1.8.0