From 57a7f963e83329c191e135c8102b0614dea6d5b4 Mon Sep 17 00:00:00 2001
From: xdh <xiefantasy@qq.com>
Date: 星期三, 19 十二月 2018 14:09:36 +0800
Subject: [PATCH] 5368 【后端】【1.4】聚魂功能开发

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py                            |   12 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py                                   |   22 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py                                    |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/MakeItemCount.py                     |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py             |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py                   |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini                                           |   22 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py                       |    7 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py                                 |   84 +++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerGatherSoul.py                       |  533 ++++++++++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_GatherSoul.py |  597 ++++++++++++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py                               |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py                                 |   30 
 PySysDB/PySysDBPY.h                                                                                                  |   32 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py                              |    6 
 ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py                                                        |   22 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py                          |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                                      |   34 +
 18 files changed, 1,385 insertions(+), 34 deletions(-)

diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index 663ac40..179bc93 100644
--- a/PySysDB/PySysDBPY.h
+++ b/PySysDB/PySysDBPY.h
@@ -1429,4 +1429,36 @@
 	char		NotifyCode;	//广播
 	DWORD		FightPower;	//增加战力
 	dict		Attr;	//属性加成
+};
+
+//聚魂表
+
+struct tagGatherSoul
+{
+	DWORD		_ItemID;	//物品ID
+	list		AttrType;	//属性类型
+	BYTE		SoulGrade;	//魂阶段
+};
+
+//聚魂合成表
+
+struct tagGatherSoulCompound
+{
+	DWORD		_TagItemID;	//合成的物品ID
+	WORD		NeedLV;	//需要的玩家等级
+	list		NeedItem; //需要的物品ID
+	WORD		NeedSoulSplinters;	//需要的聚魂碎片
+	WORD		NeedSoulCore;	//需要的核心环
+};
+
+//聚魂属性表
+
+struct tagGatherSoulAttr
+{
+	WORD		_AttrType;	//属性类型
+	char		AttrInfo1;	//基础属性-参数聚魂等级level
+	dict		AttrInfo2;	//品质系数(品质_系数|…)
+	dict		AttrInfo3;	//多属性系数
+	dict		AttrInfo4;	//初始属性(品质_属性值|…)
+	dict		AttrInfo5;	//阶段系数
 };
\ No newline at end of file
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
index 62a3bc0..79f1202 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -312,7 +312,8 @@
     Def_mitRecycleAttrFruit,  # 回收魂石
     Def_mitDogzEquipPlus,     # 神兽装备强化
     Def_mitRuneCompound,      # 符印合成
-) = range(1, 23)
+    Def_mitGatherSoulCompound,# 聚魂合成
+) = range(1, 24)
 
 #---写死的技能ID---
 Def_SkillID_AutoTruck = 62220   # 自动运镖buff
@@ -786,7 +787,10 @@
 CDBPlayerRefresh_GodWeaponLV_2,         # 神兵等级 - 类型2 193
 CDBPlayerRefresh_GodWeaponLV_3,         # 神兵等级 - 类型3 194
 CDBPlayerRefresh_GodWeaponLV_4,         # 神兵等级 - 类型4 195
-) = range(146, 196)
+CDBPlayerRefresh_SoulDust,              # 魂尘 196
+CDBPlayerRefresh_SoulSplinters,         # 聚魂碎片 197
+CDBPlayerRefresh_SoulCore,              # 核心环 198
+) = range(146, 199)
 
 TYPE_Price_Gold_Paper_Money = 5    # 金钱类型,(先用礼券,再用金子)
 TYPE_Price_Family_Contribution = 6 # 战盟贡献度(活跃度转换得来)
@@ -801,6 +805,9 @@
 TYPE_Price_TreasureScore = 25    # 寻宝积分
 TYPE_Price_BourseMoney = 26    # 交易所可购买额度
 TYPE_Price_Danjing = 27    # 丹精(丹药回收)
+TYPE_Price_SoulDust = 28    # 魂尘
+TYPE_Price_SoulSplinters = 29    # 聚魂碎片
+TYPE_Price_SoulCore = 30    # 核心环
 
 
 #以下是旧的金钱类型
@@ -828,6 +835,9 @@
                            TYPE_Price_FamilyActivity:CDBPlayerRefresh_FamilyActivity,
                            TYPE_Price_XianyuanCoin:CDBPlayerRefresh_Xianyuancoin,
                            TYPE_Price_Danjing:CDBPlayerRefresh_Danjing,
+                           TYPE_Price_SoulDust:CDBPlayerRefresh_SoulDust,
+                           TYPE_Price_SoulSplinters:CDBPlayerRefresh_SoulSplinters,
+                           TYPE_Price_SoulCore:CDBPlayerRefresh_SoulCore,
                            }
 
 # 高效战斗状态
@@ -925,8 +935,9 @@
 
 #虚拟背包类型, 从255递减
 Def_VPack_TypeList = (
+rptGatherSoul,      # 聚魂背包 254
 rptRune,            # 符印背包 255
-) = range(256 - 1, 256)
+) = range(256 - 2, 256)
 
 
 #武器的手持形式
@@ -1266,7 +1277,7 @@
 Def_IudetRuneSource = 40  # 符印来源 老号0,默认1,合成2(主要用来区分是否合成获得)
 Def_IudetWingProgressValue = 42 #羽翼精炼值
 Def_IudetCreateTime = 44 # 时效物品的创建时间
-
+Def_IudetGatherSoulLV = 46  # 聚魂等级
 # 200~300 宠物数据用
 Def_IudetPet_NPCID = 200  # npcID
 Def_IudetPet_ClassLV = 202  # 阶级
@@ -1330,7 +1341,7 @@
 )=range(5)
 
 # 战斗力模块类型
-Def_MFPType_Max = 25
+Def_MFPType_Max = 26
 ModuleFightPowerTypeList = (
 Def_MFPType_Role, # 角色 0
 Def_MFPType_Equip, # 装备(基本装备位) 1
@@ -1354,6 +1365,7 @@
 Def_MFPType_HorseSoul, # 坐骑魂石 19
 Def_MFPType_MagicWeaponSoul, # 法宝之魂 20
 Def_MFPType_Dogz, # 神兽 21
+Def_MFPType_GatherSoul, # 聚魂 22
 Def_MFPType_Other, # 其他
 
 #以下暂时没用到,改时再处理
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index ebf8152..8a31ebd 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1386,4 +1386,24 @@
 
 PacketCMD_2=0xAA
 PacketSubCMD_2=0x06
-PacketCallFunc_2=OnActWishingDrag
\ No newline at end of file
+PacketCallFunc_2=OnActWishingDrag
+
+;聚魂
+[PlayerGatherSoul]
+ScriptName = Player\PlayerGatherSoul.py
+Writer = xdh
+Releaser = xdh
+RegType = 0
+RegisterPackCount = 3
+
+PacketCMD_1=0xA5
+PacketSubCMD_1=0x18
+PacketCallFunc_1=OnGatherSoulUp
+
+PacketCMD_2=0xA5
+PacketSubCMD_2=0x19
+PacketCallFunc_2=OnGatherSoulDecompose
+
+PacketCMD_3=0xA5
+PacketSubCMD_3=0x1C
+PacketCallFunc_3=OnGatherSoulCompound
\ No newline at end of file
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index d439484..4e11f33 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -313,6 +313,9 @@
 Def_ItemType_FamilyBossFood = 50       #仙盟兽粮
 Def_ItemType_SuccessItem = 53     # 用于完成成就的物品,不存在背包
 Def_ItemType_ResetAttrPoint = 59       #洗点卷轴 使用后将某个属性一定值变为未分配属性
+Def_ItemType_GatherSoulExp = 61 #聚魂精华材料
+Def_ItemType_GatherSoul = 62 #普通聚魂
+Def_ItemType_GatherSoulCore = 63 #聚魂核心
 
 Def_ItemType_DogzEquipExp = 70  # 神兽装备经验
 
@@ -354,6 +357,7 @@
 #虚拟背包最大格子数 功能配置表对应的key
 Def_VPackCnt_Dict = {
                      ShareDefine.rptRune:'RunePackageNum',
+                     ShareDefine.rptGatherSoul:'GatherSoulPackCount',
                      }
 
 #虚拟背包可以放入的物品字典
@@ -361,6 +365,7 @@
 ShareDefine.rptRune:[Def_ItemType_Rune, Def_ItemType_RuneExp],
 ShareDefine.rptDogzItem:[Def_ItemType_DogzEquipExp, Def_ItemType_DogzEquipHorn, Def_ItemType_DogzEquipEye, 
                          Def_ItemType_DogzEquipTooth, Def_ItemType_DogzEquipClaw, Def_ItemType_DogzEquipScute],
+ShareDefine.rptGatherSoul:[Def_ItemType_GatherSoulExp, Def_ItemType_GatherSoul, Def_ItemType_GatherSoulCore],
                       }
 
 def GetItemPackType(itemType, defaultPack=IPY_GameWorld.rptItem):
@@ -1774,6 +1779,8 @@
 Def_FBMapID_XMZZ = 31010
 #神兽副本
 Def_FBMapID_Dogz = 21110
+#聚魂副本
+Def_FBMapID_GatherSoul = 31340
 #副本关闭时未拾取的物品邮件发放给玩家
 #这里只有需要的副本才配置,不做默认逻辑,防止某些副本实际不能给导致刷物品,如麒麟之府
 Def_SendUnPickItemMailMapIDList = [Def_FBMapID_IceLode, Def_FBMapID_PersonalBoss, Def_FBMapID_MunekadoTrial, 
@@ -1799,13 +1806,13 @@
 #                            + Def_FBMapID_ClearDevil
 
 # 刷新标识点在无玩家的情况下也需要刷新的地图
-Def_NoPlayerNeedProcessRefreshPointMap = [Def_FBMapID_SealDemon, Def_FBMapID_GodArea, Def_FBMapID_BossHome]
+Def_NoPlayerNeedProcessRefreshPointMap = [Def_FBMapID_SealDemon, Def_FBMapID_GodArea, Def_FBMapID_BossHome, Def_FBMapID_GatherSoul]
 
 # 可重复进的副本
 Def_NoLimitEnterCntMap = [Def_FBMapID_FamilyParty, Def_FBMapID_FamilyWar, Def_FBMapID_FamilyInvade, Def_FBMapID_ElderBattlefield]
 
 # 无玩家时不自动关闭的自伸缩副本
-Def_NoPlayerNotCloseAutoSizeMap = [Def_FBMapID_FamilyInvade, Def_FBMapID_FamilyBossMap]
+Def_NoPlayerNotCloseAutoSizeMap = [Def_FBMapID_FamilyInvade, Def_FBMapID_FamilyBossMap, Def_FBMapID_GatherSoul]
 
 # 不可切换PK模式的地图
 Def_CanNotChangeAtkModelMap = []
@@ -1861,6 +1868,7 @@
                 'SealDemon':[Def_FBMapID_SealDemon, Def_FBMapID_SealDemonEx], #封魔坛
                 'XMZZ':[Def_FBMapID_XMZZ], #仙魔之争
                 'Dogz':[Def_FBMapID_Dogz], #神兽副本
+                'GatherSoul':[Def_FBMapID_GatherSoul],#聚魂副本
                 }
 
 #特殊副本ID, 由系统分配, 进入时候不验证IsMapCopyFull
@@ -3718,6 +3726,9 @@
 Def_PDict_Rune_HoleOpenState = "Rune_HoleOpenState"  # 符印解锁状态
 Def_PDict_Rune_Data = "Rune_Data_%s"  # 符印镶嵌数据, 参数(第几孔)
 
+# 聚魂
+Def_PDict_GatherSoulHoleData = "GatherSoulHoleData_%s"  # 聚魂镶嵌数据, 参数(第几孔)
+
 # 副本 Def_PDictType_FB
 Def_PDict_FamilyBossFBAwardState = "FamilyBossFBAwardState_%s"  # 家族boss副本领奖状态%s副本id
 Def_PDict_LastEnterFBPropertyID = "LastEnterFBPropertyID_%s"  # 上次进入副本的propertyID%s副本id
@@ -4301,7 +4312,8 @@
 Def_CalcAttrFunc_DogzBattleSkill, # 助战神兽技能36
 Def_CalcAttrFunc_DogzEquip, # 神兽装备37
 Def_CalcAttrFunc_DogzEquipPlus, # 神兽装备强化38
-) = range(39)
+Def_CalcAttrFunc_GatherSoul, # 聚魂39
+) = range(40)
 
 
 # 在此列表中的功能属性,不享受百分比加成,--属性参与战力计算
@@ -4340,6 +4352,7 @@
                             ShareDefine.Def_MFPType_MagicWeapon3:[Def_CalcAttrFunc_MagicWeapon3, Def_CalcAttrFunc_Stove, Def_CalcAttrFunc_VIP],
                             ShareDefine.Def_MFPType_StoveYao:[Def_CalcAttrFunc_StoveYao],
                             ShareDefine.Def_MFPType_MagicWeaponSoul:[Def_CalcAttrFunc_MagicWeaponSoul],
+                            ShareDefine.Def_MFPType_GatherSoul:[Def_CalcAttrFunc_GatherSoul],
                             # 神兽战力同装备模块战力一致,受评分影响,装备评分相关的战力另外算
                             ShareDefine.Def_MFPType_Dogz:[Def_CalcAttrFunc_Dogz, Def_CalcAttrFunc_DogzEquipPlus],
                             ShareDefine.Def_MFPType_Other:[Def_CalcAttrFunc_Success, Def_CalcAttrFunc_FamilyTech, Def_CalcAttrFunc_EquipDecompose],
@@ -4566,6 +4579,7 @@
 Def_Cost_WishingWell, # 许愿池刷新
 Def_Cost_GodWeapon, # 神兵
 Def_Cost_FBHelpBattle, # 副本助战
+Def_Cost_FBGatherSoulBoss, # 聚魂副本BOSS召唤 40
 #-----------以下为暂时没用的,先不删除,如有新增消费点则放在这些之前------------
 Def_Cost_RefreshArrestTask, # 刷新悬赏任务
 Def_Cost_OffLineExp, # 兑换离线经验
@@ -4586,7 +4600,7 @@
 Def_Cost_Trade, # 交易
 Def_Cost_Rename, # 改名
 Def_Cost_SkillLvUp, # 技能升级
-) = range(2000, 2000 + 59)
+) = range(2000, 2000 + 60)
 
 Def_Cost_Reason_SonKey = "reason_name_son" # 消费点原因子类说明key
 
@@ -4673,6 +4687,7 @@
 Def_Cost_WishingWell:"WishingWell",
 Def_Cost_GodWeapon:"GodWeapon",
 Def_Cost_FBHelpBattle:"FBHelpBattle",
+Def_Cost_FBGatherSoulBoss:"FBGatherSoulBoss",
 }
 ## -----------------------------------------------------
 
@@ -4704,7 +4719,8 @@
 Def_GiveMoney_Truck, # 运镖
 Def_GiveMoney_FreeGoods, # 极品白拿 25
 Def_GiveMoney_BindJadeWheel, # 绑玉转盘
-) = range(1000, 1000 + 26)
+Def_GiveMoney_GatherSoulDecompose, #聚魂分解
+) = range(1000, 1000 + 27)
 
 Def_Give_Reason_SonKey = "reason_name_son" # 原因子类说明key
 
@@ -4736,6 +4752,7 @@
 Def_GiveMoney_Truck:"Truck",
 Def_GiveMoney_FreeGoods:"FreeGoods",
 Def_GiveMoney_BindJadeWheel:"BindJadeWheel",
+Def_GiveMoney_GatherSoulDecompose:"GatherSoulDecompose",
 }
 
 ##==================================================================================================
@@ -4825,7 +4842,8 @@
 ItemDel_AddKillBossCnt, # 增加BOSS可击杀次数 32
 ItemDel_DogzEquipPlus, # 神兽装备强化
 ItemDel_ChatBubbleBox, # 激活聊天气泡框
-) = range(2000, 2000 + 35)
+ItemDel_GatherSoul, # 聚魂分解
+) = range(2000, 2000 + 36)
 
 # 物品扣除类型对应信息 {类型:eventName, ...}
 ItemDelTypeDict = {
@@ -5189,7 +5207,8 @@
 PowerDownType_Dogz, #神兽召回
 PowerDownType_ResetPoint, #洗点
 PowerDownType_ResetTalent, #大师天赋重置
-) = range(10)
+PowerDownType_GatherSoul, #聚魂替换
+) = range(11)
 FightPowerDownRecordDict = {
     PowerDownType_Rune:'Rune',
     PowerDownType_LVUP:'LVUP',
@@ -5201,4 +5220,5 @@
     PowerDownType_Dogz:'DogzState',
     PowerDownType_ResetPoint:'ResetPoint',
     PowerDownType_ResetTalent:'ResetTalent',
+    PowerDownType_GatherSoul:'GatherSoul',
     } 
\ No newline at end of file
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py
index 34bbe66..c14b0e0 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py
@@ -100,7 +100,7 @@
 import PlayerExpandPackCfgMgr
 import EventReport
 import PlayerCoat
-import PlayerSuccess
+import PlayerGatherSoul
 import PlayerArrestTask
 import PlayerRune
 import IpyGameDataPY
@@ -4378,7 +4378,9 @@
     # 符印交换
     if PlayerRune.SwitchRune(curPlayer, pack_SrcBackpack, pack_DesBackPack, pack_SrcIndex, pack_DestIndex):
         return
-    
+    # 聚魂交换
+    if PlayerGatherSoul.SwitchGatherSoul(curPlayer, pack_SrcBackpack, pack_DesBackPack, pack_SrcIndex, pack_DestIndex):
+        return
     
     #时装
     if PlayerCoat.SwitchCoat(curPlayer, pack_SrcBackpack, pack_DesBackPack, pack_SrcIndex, pack_DestIndex):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/MakeItemCount.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/MakeItemCount.py
index f40d4d2..d0d1454 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/MakeItemCount.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/MakeItemCount.py
@@ -66,7 +66,8 @@
 
     if curItem.GetType() == ChConfig.Def_ItemType_Rune and runeLV:
         curItem.SetUserAttr(ShareDefine.Def_IudetRuneLV, runeLV)
-        
+    if curItem.GetType() in [ChConfig.Def_ItemType_GatherSoul,ChConfig.Def_ItemType_GatherSoulCore] and runeLV:
+        curItem.SetUserAttr(ShareDefine.Def_IudetGatherSoulLV, runeLV)
     #将物品放置玩家背包
     PlayerItemControler = ItemControler.PlayerItemControler(curPlayer)
     if not PlayerItemControler.PutInItem(IPY_GameWorld.rptItem, curItem, event=[ChConfig.ItemGive_GMMake, False, {"CMD":"MakeItemCount"}]):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py
index c5b0f45..59f1f0e 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py
@@ -42,6 +42,7 @@
                    ShareDefine.Def_MFPType_GodWeapon:"神兵",
                    ShareDefine.Def_MFPType_Dienstgrad:"称号",
                    ShareDefine.Def_MFPType_Rune:"符印",
+                   ShareDefine.Def_MFPType_GatherSoul:"聚魂",
                    ShareDefine.Def_MFPType_Horcrux:"魂器",
                    ShareDefine.Def_MFPType_MagicWeapon1:"人族",
                    ShareDefine.Def_MFPType_StoveYao:"丹药",
@@ -72,6 +73,7 @@
                      ChConfig.Def_CalcAttrFunc_GodWeapon:"神兵",
                      ChConfig.Def_CalcAttrFunc_Dienstgrad:"称号",
                      ChConfig.Def_CalcAttrFunc_Rune:"符印",
+                     ChConfig.Def_CalcAttrFunc_GatherSoul:"聚魂",
                      ChConfig.Def_CalcAttrFunc_Horcrux:"魂器",
                      ChConfig.Def_CalcAttrFunc_MagicWeapon1:"人族法宝属性",
                      ChConfig.Def_CalcAttrFunc_MagicWeapon2:"魔族法宝属性", 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
index 53d2397..b99b32d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
@@ -67,6 +67,9 @@
 Help_helpCount = 'helpCount' #该副本今日已助战次数
 Help_relation = 'relation' #该副本关系加成信息 [优先关系, 总加成]
 Help_robotJob = 'robotJob' #机器人职业 {"ObjID":job, ...}
+Help_isAuto = 'isAuto' #是否自动召唤
+Help_hasRefreshBoss = 'hasRefreshBoss' #是否已刷新boss
+Help_gsItemInfo = 'gsItemInfo' #聚魂副本物品信息 {"波数":[[{"ItemID":101, "ItemCount":10}]]}
 
 #副本结算信息通用key
 Over_dataMapID = 'dataMapID' #数据地图ID
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_GatherSoul.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_GatherSoul.py
new file mode 100644
index 0000000..e99d2ec
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_GatherSoul.py
@@ -0,0 +1,597 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GameWorldLogic.FBProcess.GameLogic_GatherSoul
+#
+# @todo:聚魂副本
+# @author xdh
+# @date 2018-12-12
+# @version 1.0
+#
+# 详细描述: 聚魂副本
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2018-12-12 21:00"""
+#-------------------------------------------------------------------------------
+
+import FBCommon
+import GameWorld
+import ItemCommon
+import IPY_GameWorld
+import GameWorldProcess
+import PyGameData
+import NPCCustomRefresh
+import ChConfig
+import ShareDefine
+import EventReport
+import PlayerControl
+import ItemControler
+import ChNPC
+
+#---副本配置对应key值---
+(
+Def_FightTime,  # 进行时间(秒)
+Def_LeaveTime,  # 退出时间(秒)
+Def_BuildNPCID,  # 建造点NPCID
+Def_BuildCnt,  # 建造点数量
+Def_BuildMark,  # 建造点标识点
+Def_BuildTime,  # 建造时间毫秒
+Def_GuardInfo,  #{守卫npcid:最大数量}
+Def_BossID,  # 黄金BOSSID
+Def_BossCostMoney,  # 召唤黄金BOSS需要金钱
+Def_NPCRefreshMark,  # 怪物刷新标识点
+Def_NPCRefreshCD,  # 小怪间隔时间毫秒
+Def_WheelRefreshCD,  # 每波间隔时间毫秒
+) = range(12)
+
+#当前副本地图的状态
+(
+FB_Step_Open,  # 副本开启
+FB_Step_Prepare,  # 建造守卫
+FB_Step_Fighting,  # 刷怪中
+FB_Step_Over,  # 副本结束
+FB_Step_Close,  # 副本关闭
+) = range(5)
+
+
+FBPlayerDict_GuardNPCID = 'FBPlayerDict_GuardNPCID'  # 需刷新的守卫ID
+FBPlayerDict_GuardNPCCnt = 'FBPlayerDict_GuardNPCCnt%s'  # 守卫已刷新数量
+FBPlayerDict_CurWheel = 'FBPlayerDict_CurWheel'  # 当前第几波怪
+FBPlayerDict_NPCIndex = 'FBPlayerDict_NPCIndex'  # 本波怪第几只
+FBPlayerDict_LastWheelEndTime = 'FBPlayerDict_LastWheelEndTime'  # 上一波结束时间
+FBPlayerDict_LastNPCRTime = 'FBPlayerDict_LastNPCRTime'  # 上一只怪物刷新时间
+FBPlayerDict_HasRefreshBoss = 'FBPlayerDict_HasRefreshBoss'  # 本波是否已刷黄金BOSS
+FBPlayerDict_AutoBoss = 'FBPlayerDict_AutoBoss'  # 是否自动刷黄金boss
+FBPlayerDict_NPCRemainCnt = 'FBPlayerDict_NPCRemainCnt'  # NPC剩余数量
+
+
+##---获得副本配置---
+#  @param None
+#  @return 配置信息
+def GetGatherSoulFBCfg():
+    return FBCommon.GetFBLineStepTime(ChConfig.Def_FBMapID_GatherSoul, 0)
+
+
+def GetGatherSoulNPCCfg():
+    return FBCommon.GetFBLineRefreshNPC(ChConfig.Def_FBMapID_GatherSoul)
+
+
+## 是否能够通过活动查询进入
+#  @param curPlayer 玩家实例
+#  @param mapID 地图ID
+#  @param lineID 线路id
+#  @param tick 时间戳
+#  @return 布尔值
+def OnEnterFBEvent(curPlayer, mapID, lineID, tick):
+    return True
+
+
+##副本玩家进入点
+# @param curPlayer 玩家实例
+# @param mapID 地图ID
+# @param lineId 分线ID
+# @param ipyEnterPosInfo 功能线路IPY配置坐标信息
+# @param tick 时间戳
+# @return posX, posY, 随机半径(可选)
+def OnGetFBEnterPos(curPlayer, mapID, lineId, ipyEnterPosInfo, tick):
+    return ipyEnterPosInfo
+
+
+##查询是否可以进入地图
+# @param ask:请求结构体(IPY_BMChangeMapAsk)
+# @param tick:时间戳
+# @return IPY_GameWorld.cme 枚举
+def OnChangeMapAsk(ask, tick):
+    return IPY_GameWorld.cmeAccept
+
+
+##开启副本
+# @param tick 时间戳
+# @return 返回值无意义
+# @remarks 开启副本
+def OnOpenFB(tick):
+    #刷建造点
+    gatherSoulFBCfg = GetGatherSoulFBCfg()
+    NPCCustomRefresh.SetNPCRefresh(gatherSoulFBCfg[Def_BuildMark], [(gatherSoulFBCfg[Def_BuildNPCID], 1)], 1, gatherSoulFBCfg[Def_BuildCnt])
+    return
+
+##关闭副本
+# @param tick 时间戳
+# @return 无意义
+# @remarks 
+def OnCloseFB(tick):
+    __DoGatherSoulOver()
+    return
+
+## 进副本
+#  @param curPlayer
+#  @param tick
+#  @return None
+def DoEnterFB(curPlayer, tick):
+    PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default * 3)
+    playerID = curPlayer.GetPlayerID()
+    playerLV = curPlayer.GetLV()
+    mapID = GameWorld.GetMap().GetMapID()
+    mapID = FBCommon.GetRecordMapID(mapID)
+    gameFB = GameWorld.GetGameFB()
+    lineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ReqFBFuncLine)
+    GameWorld.DebugLog("DoEnterFB...lineID=%s,playerLV=%s" % (lineID, playerLV), playerID)
+    hadDelTicket = FBCommon.GetHadDelTicket(curPlayer)
+    if not hadDelTicket:
+        FBCommon.SetHadDelTicket(curPlayer)
+        FBCommon.SetFBPropertyMark(lineID)
+        EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_GatherSoul, 0, ChConfig.CME_Log_Start)
+    
+    fbStep = gameFB.GetFBStep()
+    if fbStep < FB_Step_Prepare:
+        FBCommon.SetFBStep(FB_Step_Prepare, tick)
+        
+    if fbStep < FB_Step_Over:
+        notify_tick = GetGatherSoulFBCfg()[Def_FightTime] * 1000 - (tick - GameWorld.GetGameWorld().GetOpenFBTick())
+        curPlayer.Sync_TimeTick(IPY_GameWorld.tttTowerTake, 0, max(notify_tick, 0), True)
+    else:
+        return
+    DoFBHelp(curPlayer, tick)
+    return
+
+
+##玩家退出副本
+# @param curPlayer 玩家实例
+# @param tick 时间戳
+# @return 无意义
+def DoExitFB(curPlayer, tick):
+    PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default)
+    fbStep = GameWorld.GetGameFB().GetFBStep()
+    if fbStep >= FB_Step_Over:
+        GameWorldProcess.CloseFB(tick)
+    return
+
+
+##玩家主动离开副本.
+# @param curPlayer 玩家实例
+# @param tick 时间戳
+# @return 返回值无意义
+def DoPlayerLeaveFB(curPlayer, tick):
+    __DoGatherSoulOver()
+    GameWorldProcess.CloseFB(tick)
+    return  
+
+
+## 获得副本帮助信息
+#  @param curPlayer 当前玩家(被通知对象)
+#  @param tick 当前时间
+#  @return None
+def DoFBHelp(curPlayer, tick):
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    if fbStep > FB_Step_Fighting:
+        return
+    curWheel = gameFB.GetGameFBDictByKey(FBPlayerDict_CurWheel)
+    maxWheel = len(GetGatherSoulNPCCfg())
+    curWheel = 0 if fbStep == FB_Step_Prepare else min(curWheel+1, maxWheel)
+    gatherSoulFBCfg = GetGatherSoulFBCfg()
+    guardDict = {}
+    for npcid in gatherSoulFBCfg[Def_GuardInfo]:
+        guardDict[npcid] = gameFB.GetGameFBDictByKey(FBPlayerDict_GuardNPCCnt%npcid)
+    hasRefreshBoss = gameFB.GetGameFBDictByKey(FBPlayerDict_HasRefreshBoss)
+    isAutoBoss = gameFB.GetGameFBDictByKey(FBPlayerDict_AutoBoss)
+
+    itemDict = PyGameData.g_gathersoulfbAwardDict.get(curPlayer.GetID(), {})
+    helpItemInfo = {}
+    for wheel, itemList in itemDict:
+        helpItemInfo[str(wheel)] = FBCommon.GetJsonItemList(itemList)
+    helpDict = {FBCommon.Help_wheel:curWheel, 
+                FBCommon.Help_step:fbStep, 
+                FBCommon.Help_npc:FBCommon.GetJsonNPCKillList(guardDict),
+                FBCommon.Help_isAuto:isAutoBoss,
+                FBCommon.Help_isAuto:hasRefreshBoss,
+                FBCommon.Help_gsItemInfo:helpItemInfo,
+                }
+    #副本帮助
+    GameWorld.DebugLog("DoFBHelp %s" % str(helpDict))
+    FBCommon.Notify_FBHelp(curPlayer, helpDict)
+    return
+
+
+##---副本总逻辑计时器---
+# @param tick:时间戳
+# @return 无意义
+# @remarks 副本总逻辑计时器
+def OnProcess(tick):
+    fbStep = GameWorld.GetGameFB().GetFBStep()
+    
+    # 副本进行中
+    if fbStep == FB_Step_Fighting:
+        __DoLogic_FB_Fighting(tick)
+    # 副本结束
+    elif fbStep == FB_Step_Over:
+        __DoLogic_FB_Over(tick)
+    
+    return
+
+
+def __CheckNPCRefresh(tick):
+    gameFB = GameWorld.GetGameFB()
+    
+    gatherSoulFBCfg = GetGatherSoulFBCfg()
+    
+    lastWheelEndTime = gameFB.GetGameFBDictByKey(FBPlayerDict_LastWheelEndTime)
+    if lastWheelEndTime and tick - lastWheelEndTime < gatherSoulFBCfg[Def_WheelRefreshCD]:
+        return
+    lastNPCRTime = gameFB.GetGameFBDictByKey(FBPlayerDict_LastNPCRTime)
+    if lastNPCRTime and tick - lastNPCRTime < gatherSoulFBCfg[Def_NPCRefreshCD]:
+        return
+    
+    curWheel = gameFB.GetGameFBDictByKey(FBPlayerDict_CurWheel)
+    curNPCIndex = gameFB.GetGameFBDictByKey(FBPlayerDict_NPCIndex)
+    npcRereshList = GetGatherSoulNPCCfg()  #[[npcid,npcid,],[],[]]
+    if curWheel >= len(npcRereshList):
+        return
+    npcList = npcRereshList[curWheel]
+    if curNPCIndex >= len(npcList):
+        return
+    
+    GameWorld.DebugLog('    开始刷第%s波第%s只怪!' % (curWheel + 1, curNPCIndex + 1))
+    
+    refreshNPCid = npcList[curNPCIndex]  #本次要刷新的NPC
+#    npcCntDict = {}  #标识点对应数量
+    
+#    gameNPC = GameWorld.GetNPCManager()
+#    for i in xrange(gameNPC.GetCustomNPCRefreshCount()):
+#        npcRefresh = gameNPC.GetCustomNPCRefreshAt(i)
+#        rmark = npcRefresh.GetRefreshMark()
+#        npcCntDict[rmark] = npcCntDict.get(rmark, npcRefresh.GetCount())
+    __RefreshNPC(refreshNPCid)
+    
+    if curNPCIndex + 1 >= len(npcList):
+        if curWheel + 1 >= len(npcRereshList):
+            GameWorld.DebugLog('    全部小怪刷完!')
+ 
+    gameFB.SetGameFBDict(FBPlayerDict_NPCIndex, curNPCIndex + 1)
+    gameFB.SetGameFBDict(FBPlayerDict_LastNPCRTime, tick)
+    
+    curPlayer = FBCommon.GetCurSingleFBPlayer()
+    if curPlayer:
+        DoFBHelp(curPlayer, tick)
+    return
+
+def __RefreshNPC(refreshNPCid):
+    #刷1只怪物
+    gameFB = GameWorld.GetGameFB()
+    curRemainCnt = gameFB.GetGameFBDictByKey(FBPlayerDict_NPCRemainCnt)
+    curMaxCnt = curRemainCnt + 1
+    gatherSoulFBCfg = GetGatherSoulFBCfg()
+    refreshMark = gatherSoulFBCfg[Def_NPCRefreshMark]
+    NPCCustomRefresh.SetNPCRefresh(refreshMark, [refreshNPCid], curMaxCnt, 1)
+    gameFB.SetGameFBDict(FBPlayerDict_NPCRemainCnt, curMaxCnt)
+    return
+
+## 副本进行中
+#  @param tick:时间戳
+#  @return 无意义
+def __DoLogic_FB_Fighting(tick):
+    __CheckNPCRefresh(tick)
+    __CheckAutoRefreshGoldBoss(tick)
+    
+    fbCfg = GetGatherSoulNPCCfg()
+    # 间隔未到
+    if tick - GameWorld.GetGameWorld().GetOpenFBTick() < fbCfg[Def_FightTime] * 1000:
+        return
+    
+    __DoGatherSoulOver()
+    return
+
+        
+##副本关闭中
+# @param tick:时间戳
+# @return 无意义
+# @remarks 副本关闭中
+def __DoLogic_FB_Over(tick):
+
+    #gameFB = GameWorld.GetGameFB()
+    fbCfg = GetGatherSoulNPCCfg()
+    # 间隔未到
+    if tick - GameWorld.GetGameFB().GetFBStepTick() < fbCfg[Def_LeaveTime] * 1000:
+        return
+    
+    #副本关闭
+    GameWorldProcess.CloseFB(tick)
+    FBCommon.SetFBStep(FB_Step_Close, tick)
+    return
+
+def DoFB_NPCDead(curNPC):
+    npcRereshList = GetGatherSoulNPCCfg()
+    npcidlist = [GetGatherSoulFBCfg()[Def_BossID]]
+    for nlist in npcRereshList:
+        npcidlist += nlist
+    if curNPC.GetNPCID() not in npcidlist:
+        return
+    
+    gameFB = GameWorld.GetGameFB()
+    curRemainCnt = gameFB.GetGameFBDictByKey(FBPlayerDict_NPCRemainCnt)
+    newRemainCnt = max(0, curRemainCnt - 1)
+    gameFB.SetGameFBDict(FBPlayerDict_NPCRemainCnt, newRemainCnt)
+    
+    curWheel = gameFB.GetGameFBDictByKey(FBPlayerDict_CurWheel)
+    curNPCIndex = gameFB.GetGameFBDictByKey(FBPlayerDict_NPCIndex)
+    
+    if newRemainCnt <= 0 and curNPCIndex >= len(npcRereshList[curWheel]):
+        #本波的怪都死掉了
+        gameFB.SetGameFBDict(FBPlayerDict_CurWheel, curWheel + 1)
+        gameFB.SetGameFBDict(FBPlayerDict_HasRefreshBoss, 0)
+        curPlayer = FBCommon.GetCurSingleFBPlayer()
+        if curPlayer:
+            DoFBHelp(curPlayer, GameWorld.GetGameWorld().GetTick())
+        if curWheel + 1>=len(npcRereshList):
+            #所有波的怪都死了,结束
+            __DoGatherSoulOver()
+        else:
+            #进入下一波
+            gameFB.SetGameFBDict(FBPlayerDict_NPCIndex, 0)
+            gameFB.SetGameFBDict(FBPlayerDict_LastWheelEndTime, GameWorld.GetGameWorld().GetTick())
+            gameFB.SetGameFBDict(FBPlayerDict_LastNPCRTime, 0)
+            if curPlayer:
+                curPlayer.Sync_TimeTick(IPY_GameWorld.tttLeaveFamilyWar, 0, GetGatherSoulFBCfg()[Def_WheelRefreshCD], True)
+                    
+    return
+
+##是否可以夺旗
+# @param curPlayer 玩家实例
+# @param curNPC NPC实例
+# @param tick 时间戳
+# @return 无意义
+# @remarks
+def OnCanCollect(curPlayer, curNPC, tick):
+    gameFB = GameWorld.GetGameFB()
+    guardNPCID = gameFB.GetGameFBDictByKey(FBPlayerDict_GuardNPCID)
+    gatherSoulFBCfg = GetGatherSoulFBCfg()
+    guardMaxCntDict = gatherSoulFBCfg[Def_GuardInfo]
+    if guardNPCID not in guardMaxCntDict:
+        return False
+    curCnt = gameFB.GetGameFBDictByKey(FBPlayerDict_GuardNPCCnt % guardNPCID)
+    if curCnt >= guardMaxCntDict[guardNPCID]:
+        GameWorld.Log('    该守卫已满,不可再建造 guardNPCID=%s,curCnt=%s' % (guardNPCID, curCnt))
+        return False
+    return True
+
+
+##副本中,占领NPC的Loading时间.
+# @param curPlayer 玩家实例
+# @param curNPC NPC实例
+# @return 返回值, Loading时间
+# @remarks 副本中,占领NPC的Loading时间
+def GetFBPrepareTime(curPlayer, curNPC):
+    return GetGatherSoulFBCfg()[Def_BuildTime]
+
+
+##玩家收集成功(塔, 旗)
+# @param curPlayer 玩家实例
+# @param tick 时间戳
+# @return 无意义
+# @remarks
+def OnCollectOK(curPlayer, npcID, tick):
+    tagObj = curPlayer.GetActionObj()
+    if not tagObj:
+        return
+    if tagObj.GetGameObjType() != IPY_GameWorld.gotNPC:
+        return
+    
+    curNPC = GameWorld.GetNPCManager().GetNPCByIndex(tagObj.GetIndex())
+    if not curNPC:
+        return
+    gatherSoulFBCfg = GetGatherSoulFBCfg()
+    if curNPC.GetNPCID() != gatherSoulFBCfg[Def_BuildNPCID]:
+        return
+    gameFB = GameWorld.GetGameFB()
+    guardNPCID = gameFB.GetGameFBDictByKey(FBPlayerDict_GuardNPCID)
+    if not guardNPCID:
+        GameWorld.ErrLog('采集前未指定要建造NPCID', curPlayer.GetID())
+        return
+    ChNPC.OnCollectEnd(curPlayer, curNPC)
+    #刷守卫
+    NPCCustomRefresh.SetNPCRefresh(gatherSoulFBCfg[Def_BuildMark], [(guardNPCID, 1)], 1, 1)
+    key = FBPlayerDict_GuardNPCCnt % guardNPCID
+    gameFB.SetGameFBDict(key, gameFB.GetGameFBDictByKey(key) + 1)
+    return
+
+
+## 副本行为
+#  @param curPlayer 玩家
+#  @param actionType 行为类型
+#  @param actionInfo 行为信息
+#  @param tick 当前时间
+#  @return None
+def DoFBAction(curPlayer, actionType, actionInfo, tick):
+    gameFB = GameWorld.GetGameFB()
+    gatherSoulFBCfg = GetGatherSoulFBCfg()
+    fbStep = gameFB.GetFBStep()
+    if actionType == 0:  #建造守卫 
+        if actionInfo not in gatherSoulFBCfg[Def_GuardInfo]:
+            return
+        gameFB.SetGameFBDict(FBPlayerDict_GuardNPCID, actionInfo)
+        
+    elif actionType == 1:  #开始刷怪 
+        if fbStep != FB_Step_Prepare:
+            return
+        FBCommon.SetFBStep(FB_Step_Fighting, tick)
+        FBCommon.AddEnterFBCount(curPlayer, ChConfig.Def_FBMapID_GatherSoul)
+    elif actionType == 2:  #召唤黄金BOSS actionInfo 0-召唤1次 1-自动召唤 2-取消自动召唤
+        if fbStep != FB_Step_Fighting:
+            return
+        if actionInfo == 0:
+            if gameFB.GetGameFBDictByKey(FBPlayerDict_HasRefreshBoss):
+                #本波已刷黄金BOSS
+                PlayerControl.NotifyCode(curPlayer, 'JHCallForBoss1')
+                return
+            #判断钱
+            costMoney = gatherSoulFBCfg[Def_BossCostMoney]
+            costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, ShareDefine.TYPE_Price_Gold_Paper_Money, costMoney)
+            if not costMoneyList:
+                return
+            for moneyType, moneyCnt in costMoneyList:
+                PlayerControl.PayMoney(curPlayer, moneyType, moneyCnt, ChConfig.Def_Cost_FBGatherSoulBoss)
+            #立即刷
+            __RefreshNPC(gatherSoulFBCfg[Def_BossID])
+            gameFB.SetGameFBDict(FBPlayerDict_HasRefreshBoss, 1)
+        elif actionInfo == 1:
+            if gameFB.GetGameFBDictByKey(FBPlayerDict_AutoBoss):
+                GameWorld.DebugLog('已经是自动召唤BOSS状态!')
+                return
+            gameFB.SetGameFBDict(FBPlayerDict_AutoBoss, 1)
+        elif actionInfo == 2:
+            if not gameFB.GetGameFBDictByKey(FBPlayerDict_AutoBoss):
+                GameWorld.DebugLog('不是自动召唤BOSS状态,不需要取消!')
+                return
+            gameFB.SetGameFBDict(FBPlayerDict_AutoBoss, 0)
+            
+    DoFBHelp(curPlayer, tick)
+    return
+
+def __CheckAutoRefreshGoldBoss(tick):
+    ##自动召唤黄金BOSS
+    gameFB = GameWorld.GetGameFB()
+    if not gameFB.GetGameFBDictByKey(FBPlayerDict_AutoBoss):
+        return
+    curPlayer = FBCommon.GetCurSingleFBPlayer()
+    if not curPlayer:
+        gameFB.SetGameFBDict(FBPlayerDict_AutoBoss, 0)
+        return
+    fbStep = gameFB.GetFBStep()
+    if fbStep != FB_Step_Fighting:
+        gameFB.SetGameFBDict(FBPlayerDict_AutoBoss, 0)
+        return
+    if gameFB.GetGameFBDictByKey(FBPlayerDict_HasRefreshBoss):
+        #本波已刷黄金BOSS
+        return
+    
+    gatherSoulFBCfg = GetGatherSoulFBCfg()
+    costMoney = gatherSoulFBCfg[Def_BossCostMoney]
+    costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, ShareDefine.TYPE_Price_Gold_Paper_Money, costMoney, False)
+    if not costMoneyList:
+        PlayerControl.NotifyCode(curPlayer, 'JHCallForBoss2')
+        gameFB.SetGameFBDict(FBPlayerDict_AutoBoss, 0)
+    else:
+        for moneyType, moneyCnt in costMoneyList:
+            PlayerControl.PayMoney(curPlayer, moneyType, moneyCnt, ChConfig.Def_Cost_FBGatherSoulBoss)
+        #立即刷
+        __RefreshNPC(gatherSoulFBCfg[Def_BossID])
+        
+        gameFB.SetGameFBDict(FBPlayerDict_HasRefreshBoss, 1)
+    DoFBHelp(curPlayer, tick)
+    return
+
+
+## 是否副本复活
+#  @param None
+#  @return 是否副本复活
+def OnPlayerReborn():
+    return True
+
+
+##玩家死亡.
+# @param curPlayer:死亡的玩家 
+# @param tick 时间戳
+# @return 返回值无意义
+# @remarks 玩家主动离开副本.
+def DoPlayerDead(curPlayer):
+    
+    return
+
+
+## 检查是否可攻击, 主判定不可攻击的情况,其他逻辑由外层决定
+#  @param attacker 攻击方
+#  @param defender 防守方
+#  @return bool
+def CheckCanAttackTagObjInFB(attacker, defender):
+    gameFB = GameWorld.GetGameFB()
+    if gameFB.GetFBStep() != FB_Step_Fighting:
+        return False
+    return True
+
+def KillGatherSoulNPCDropAward(itemID, itemCnt, isBind):
+    ##掉落奖励 {wheel:[[itemid,itemCnt,isBind]]}
+    gameFB = GameWorld.GetGameFB()
+    curWheel = gameFB.GetGameFBDictByKey(FBPlayerDict_CurWheel) + 1
+    ownerID = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_SingleFBPlayerID)
+    if ownerID not in PyGameData.g_gathersoulfbAwardDict:
+        PyGameData.g_gathersoulfbAwardDict[ownerID] = {}
+    if curWheel not in PyGameData.g_gathersoulfbAwardDict[ownerID]:
+        PyGameData.g_gathersoulfbAwardDict[ownerID][curWheel] = []
+    PyGameData.g_gathersoulfbAwardDict[ownerID][curWheel].append([itemID, itemCnt, isBind])
+    curPlayer = FBCommon.GetCurSingleFBPlayer()
+    if curPlayer:
+        DoFBHelp(curPlayer, 0)
+    return
+
+## 副本结束处理
+def __DoGatherSoulOver():
+    gameFB = GameWorld.GetGameFB()
+    if gameFB.GetFBStep() == FB_Step_Over:
+        return
+    
+    tick = GameWorld.GetGameWorld().GetTick()
+    # 进入离开阶段
+    FBCommon.SetFBStep(FB_Step_Over, tick)
+    ownerID = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_SingleFBPlayerID)
+    itemDict = PyGameData.g_gathersoulfbAwardDict.pop(ownerID, {})
+    totalItemList = []
+    for itemList in itemDict.values():
+        totalItemList += itemList
+    GameWorld.Log('   副本结束处理  itemDict=%s'%itemDict, ownerID)
+    curPlayer = FBCommon.GetCurSingleFBPlayer()
+    if not curPlayer:
+        #奖励直接发邮件
+        PlayerControl.SendMailByKey('JHBagFull2', [ownerID], totalItemList)
+        
+        GameWorldProcess.CloseFB(tick)
+        return
+    needSpace = len(totalItemList)
+    emptySpace = ItemCommon.GetItemPackSpace(curPlayer, ShareDefine.rptGatherSoul, needSpace)
+    isSendMail = int(needSpace > emptySpace) # 是否发送邮件
+    if isSendMail:
+        PlayerControl.SendMailByKey('JHBagFull2', [curPlayer.GetPlayerID()], totalItemList)
+        GameWorld.DebugLog("背包空间不够,发送邮件: mailItemList=%s" % str(totalItemList), curPlayer.GetPlayerID())
+    else:
+        for itemID, itemCnt, isBind in totalItemList:
+            ItemControler.GivePlayerItem(curPlayer, itemID, itemCnt, isBind, [ShareDefine.rptGatherSoul],
+                                            event=["GatherSoulFB", False, {}])
+            
+    fbCfg = GetGatherSoulFBCfg()
+    costTime = tick - GameWorld.GetGameWorld().GetOpenFBTick()
+
+    itemInfo = FBCommon.GetJsonItemList(totalItemList)
+    __SendOverInfo(curPlayer, {FBCommon.Over_isPass:1, FBCommon.Over_costTime:costTime, FBCommon.Over_itemInfo:itemInfo})
+    
+    FBCommon.Sync_Player_TimeTick(IPY_GameWorld.tttLeaveMap, fbCfg[Def_LeaveTime] * 1000)
+    return
+
+
+## 发送挑战结果信息
+def __SendOverInfo(curPlayer, overDict):
+    overDict[FBCommon.Over_dataMapID] = ChConfig.Def_FBMapID_GatherSoul
+    #overDict[FBCommon.Over_lineID] = FBCommon.GetFBPropertyMark()
+    GameWorld.DebugLog("__SendOverInfo overDict=%s" % (str(overDict)), curPlayer.GetPlayerID())
+    FBCommon.Notify_FB_Over(curPlayer, overDict)
+    return
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index 3d06030..a6f662f 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1130,6 +1130,29 @@
                         ("DWORD", "FightPower", 0),
                         ("dict", "Attr", 0),
                         ),
+
+                "GatherSoul":(
+                        ("DWORD", "ItemID", 1),
+                        ("list", "AttrType", 0),
+                        ("BYTE", "SoulGrade", 0),
+                        ),
+
+                "GatherSoulCompound":(
+                        ("DWORD", "TagItemID", 1),
+                        ("WORD", "NeedLV", 0),
+                        ("list", "NeedItem", 0),
+                        ("WORD", "NeedSoulSplinters", 0),
+                        ("WORD", "NeedSoulCore", 0),
+                        ),
+
+                "GatherSoulAttr":(
+                        ("WORD", "AttrType", 1),
+                        ("char", "AttrInfo1", 0),
+                        ("dict", "AttrInfo2", 0),
+                        ("dict", "AttrInfo3", 0),
+                        ("dict", "AttrInfo4", 0),
+                        ("dict", "AttrInfo5", 0),
+                        ),
                 }
 
 
@@ -3435,6 +3458,55 @@
     def GetNotifyCode(self): return self.NotifyCode # 广播
     def GetFightPower(self): return self.FightPower # 增加战力
     def GetAttr(self): return self.Attr # 属性加成
+
+# 聚魂表
+class IPY_GatherSoul():
+    
+    def __init__(self):
+        self.ItemID = 0
+        self.AttrType = []
+        self.SoulGrade = 0
+        return
+        
+    def GetItemID(self): return self.ItemID # 物品ID
+    def GetAttrType(self): return self.AttrType # 属性类型
+    def GetSoulGrade(self): return self.SoulGrade # 魂阶段
+
+# 聚魂合成表
+class IPY_GatherSoulCompound():
+    
+    def __init__(self):
+        self.TagItemID = 0
+        self.NeedLV = 0
+        self.NeedItem = []
+        self.NeedSoulSplinters = 0
+        self.NeedSoulCore = 0
+        return
+        
+    def GetTagItemID(self): return self.TagItemID # 合成的物品ID
+    def GetNeedLV(self): return self.NeedLV # 需要的玩家等级
+    def GetNeedItem(self): return self.NeedItem # 需要的物品ID
+    def GetNeedSoulSplinters(self): return self.NeedSoulSplinters # 需要的聚魂碎片
+    def GetNeedSoulCore(self): return self.NeedSoulCore # 需要的核心环
+
+# 聚魂属性表
+class IPY_GatherSoulAttr():
+    
+    def __init__(self):
+        self.AttrType = 0
+        self.AttrInfo1 = ""
+        self.AttrInfo2 = {}
+        self.AttrInfo3 = {}
+        self.AttrInfo4 = {}
+        self.AttrInfo5 = {}
+        return
+        
+    def GetAttrType(self): return self.AttrType # 属性类型
+    def GetAttrInfo1(self): return self.AttrInfo1 # 基础属性-参数聚魂等级level
+    def GetAttrInfo2(self): return self.AttrInfo2 # 品质系数(品质_系数|…)
+    def GetAttrInfo3(self): return self.AttrInfo3 # 多属性系数
+    def GetAttrInfo4(self): return self.AttrInfo4 # 初始属性(品质_属性值|…)
+    def GetAttrInfo5(self): return self.AttrInfo5 # 阶段系数
 
 
 def Log(msg, playerID=0, par=0):
@@ -3670,6 +3742,12 @@
         self.ipyIceLodeStarAwardLen = len(self.ipyIceLodeStarAwardCache)
         self.ipyGodWeaponEffectCache = self.__LoadFileData("GodWeaponEffect", IPY_GodWeaponEffect)
         self.ipyGodWeaponEffectLen = len(self.ipyGodWeaponEffectCache)
+        self.ipyGatherSoulCache = self.__LoadFileData("GatherSoul", IPY_GatherSoul)
+        self.ipyGatherSoulLen = len(self.ipyGatherSoulCache)
+        self.ipyGatherSoulCompoundCache = self.__LoadFileData("GatherSoulCompound", IPY_GatherSoulCompound)
+        self.ipyGatherSoulCompoundLen = len(self.ipyGatherSoulCompoundCache)
+        self.ipyGatherSoulAttrCache = self.__LoadFileData("GatherSoulAttr", IPY_GatherSoulAttr)
+        self.ipyGatherSoulAttrLen = len(self.ipyGatherSoulAttrCache)
         Log("IPY_FuncConfig count=%s" % len(self.ipyFuncConfigDict))
         Log("IPY_DataMgr InitOK!")
         return
@@ -4046,6 +4124,12 @@
     def GetIceLodeStarAwardByIndex(self, index): return self.ipyIceLodeStarAwardCache[index]
     def GetGodWeaponEffectCount(self): return self.ipyGodWeaponEffectLen
     def GetGodWeaponEffectByIndex(self, index): return self.ipyGodWeaponEffectCache[index]
+    def GetGatherSoulCount(self): return self.ipyGatherSoulLen
+    def GetGatherSoulByIndex(self, index): return self.ipyGatherSoulCache[index]
+    def GetGatherSoulCompoundCount(self): return self.ipyGatherSoulCompoundLen
+    def GetGatherSoulCompoundByIndex(self, index): return self.ipyGatherSoulCompoundCache[index]
+    def GetGatherSoulAttrCount(self): return self.ipyGatherSoulAttrLen
+    def GetGatherSoulAttrByIndex(self, index): return self.ipyGatherSoulAttrCache[index]
 
 IPYData = IPY_DataMgr()
 def IPY_Data(): return IPYData
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 a4bcf8a..76c8ac9 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
@@ -1029,6 +1029,8 @@
         if packIndex == ShareDefine.rptRune:
             runeSource = tagItem.GetUserAttr(ShareDefine.Def_IudetRuneSource) or 1
             setItemKeyData = GetRuneItemKeyData(tagItem.GetItemTypeID(), tagItem.GetUserAttr(ShareDefine.Def_IudetRuneLV), source=runeSource)
+        elif packIndex == ShareDefine.rptGatherSoul:
+            setItemKeyData = GetGatherSoulItemKeyData(tagItem.GetItemTypeID(), tagItem.GetUserAttr(ShareDefine.Def_IudetGatherSoulLV))
 
         refreshPlaceList = []
         for place in xrange(ItemCommon.GetVPackCnt(packIndex)):
@@ -1138,7 +1140,7 @@
         isBind = tagItem.GetIsBind()
         isNeedRecord = False
         # 目前暂只记录放入背包的
-        if packIndex in [IPY_GameWorld.rptItem, ShareDefine.rptTreasure, ShareDefine.rptRune]:
+        if packIndex in [IPY_GameWorld.rptItem, ShareDefine.rptTreasure, ShareDefine.rptRune, ShareDefine.rptGatherSoul]:
             isNeedRecord = ItemNeedRecord(tagItem) or isForceEvent
         putResult = False
         
@@ -1378,6 +1380,14 @@
 def IsRuneItemNeedRecord(curItem, plusLV):
     return plusLV > 0 or curItem.GetItemColor() >= ChConfig.Def_Quality_Orange
 
+# 聚魂物品存储字典数值数据结构: 前5位为物品ID, 6~8位为强化等级
+def GetGatherSoulItemKeyData(itemID, GatherSoulLV):
+    return min(GatherSoulLV, 999) * 100000 + itemID
+def GetGatherSoulItemID(keyData): return keyData % 100000
+def GetGatherSoulItemPlusLV(keyData): return keyData % 100000000 / 100000
+def IsGatherSoulItemNeedRecord(curItem, plusLV):
+    return plusLV > 0 or curItem.GetItemColor() >= ChConfig.Def_Quality_Orange
+
 def SetVPackItemKeyData(curPlayer, packIndex, place, keyData, isSync=True):
     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_VPackItem % (packIndex, place), keyData)
     if isSync:
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py
index 5c450f6..293b4bc 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py
@@ -1849,6 +1849,13 @@
             itemName = str(itemID) if not curItemData else  curItemData.GetName()
             itemName = "%s LV%s" % (itemName, plusLV + 1)
             isNeedRecord = curItemData and ItemControler.IsRuneItemNeedRecord(curItemData, plusLV)
+        if packIndex == ShareDefine.rptGatherSoul:
+            itemID = ItemControler.GetGatherSoulItemID(itemKeyData)
+            plusLV = ItemControler.GetGatherSoulItemPlusLV(itemKeyData)
+            curItemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
+            itemName = str(itemID) if not curItemData else  curItemData.GetName()
+            itemName = "%s LV%s" % (itemName, plusLV + 1)
+            isNeedRecord = curItemData and ItemControler.IsGatherSoulItemNeedRecord(curItemData, plusLV)
             
         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_VPackItem % (packIndex, place), 0)
         if isNeedRecord:
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
index 91ae3d5..8971a63 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
@@ -47,7 +47,7 @@
 import BossHurtMng
 import PlayerSuperMarket
 import GameLogic_FamilyInvade
-#import GameLogic_MunekadoTrial
+import GameLogic_GatherSoul
 import FormulaControl
 import PlayerMagicWeapon
 import PlayerBossReborn
@@ -4184,9 +4184,16 @@
                 ownerType, ownerID = hurtType, hurtID
                 itemCnt = moneyValue if itemID == moneyID else 1
                 isBind = dropIDBindDict.get(itemID, 1)
-                
+            
             curItem = self.__CreateDropItem(curNPC, itemID, itemCnt, isBind)
             if not curItem:
+                continue
+            
+            if mapID == ChConfig.Def_FBMapID_GatherSoul:#聚魂副本特殊处理
+                GameLogic_GatherSoul.KillGatherSoulNPCDropAward(itemID, itemCnt, isBind)
+                dropItemDataStr = ChItem.GetMapDropItemDataStr(curItem)
+                self.SendVirtualItemDrop(ownerPlayer, itemID, resultX, resultY, dropItemDataStr)
+                curItem.Clear()
                 continue
             
             if isDropInItemPack:
@@ -4196,17 +4203,22 @@
                 if ItemControler.DoLogic_PutItemInPack(ownerPlayer, curItem, True, True,
                                                        event=["NPCDrop", False, {"npcID":npcID}]):
                     #通知客户端
-                    vItemDrop = ChPyNetSendPack.tagMCVirtualItemDrop()
-                    vItemDrop.ItemTypeID = itemID
-                    vItemDrop.PosX = resultX
-                    vItemDrop.PosY = resultY
-                    vItemDrop.UserData = dropItemDataStr
-                    vItemDrop.UserDataLen = len(vItemDrop.UserData)
-                    NetPackCommon.SendFakePack(ownerPlayer, vItemDrop)
+                    self.SendVirtualItemDrop(ownerPlayer, itemID, resultX, resultY, dropItemDataStr)
+                    
             else:
                 self.__MapCreateItem(curItem, resultX, resultY, ownerType, ownerID)
         return
     
+    def SendVirtualItemDrop(self, player, itemID, posX, posY, userDataStr):
+        #通知客户端
+        vItemDrop = ChPyNetSendPack.tagMCVirtualItemDrop()
+        vItemDrop.ItemTypeID = itemID
+        vItemDrop.PosX = posX
+        vItemDrop.PosY = posY
+        vItemDrop.UserData = userDataStr
+        vItemDrop.UserDataLen = len(vItemDrop.UserData)
+        NetPackCommon.SendFakePack(player, vItemDrop)
+        return
     #---------------------------------------------------------------------
     ## NPC被杀死逻辑处理
     #  @param self 类实例
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 ad65c9f..f869d0c 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -76,7 +76,7 @@
 import PlayerEquipDecompose
 import PlayerCoat
 import PlayerGreatMaster
-import PlayerCostVIP
+import PlayerGatherSoul
 import PlayerMergeKing
 import PlayerMergePK
 import GameFuncComm
@@ -564,7 +564,8 @@
     SyncChatBubbleBoxState(curPlayer)
     # 副本助战
     FBHelpBattle.DoPlayerLogin(curPlayer)
-    
+    # 聚魂
+    PlayerGatherSoul.PlayerLogin(curPlayer)
     curPlayer.SetState(0)   # 脱机挂恢复为正常上线
     curPlayer.SetFacePic(0) # 通知数据库是否保存还是下线,做一次恢复,1为保存 0为正常下线
     tjgTime = PlayerTJG.GetTJGTime(curPlayer)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
index 1cf419a..327f133 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -64,7 +64,7 @@
 import PlayerGameEvent
 import EventReport
 import PlayerTeHui
-import GameLogic_XMZZ
+import PlayerGatherSoul
 import PlayerSuccess
 import PlayerPet
 import PlayerGreatMaster
@@ -4089,6 +4089,7 @@
         PlayerFamilyTech.CalcFamilyTechAttr(curPlayer)
         PlayerEquipDecompose.RefreshEDAttr(curPlayer)
         PlayerDogz.RefreshDogzAttr(curPlayer)
+        PlayerGatherSoul.RefreshGatherSoulAttr(curPlayer)
         self.RefreshAllState(isForce=True)
         GameWorld.DebugLog("End ReCalcAllState!!!")
         return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerGatherSoul.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerGatherSoul.py
new file mode 100644
index 0000000..3f29c33
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerGatherSoul.py
@@ -0,0 +1,533 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+#-------------------------------------------------------------------------------
+#
+##@package Player.PlayerGatherSoul
+#
+# @todo:玩家聚魂
+# @author xdh
+# @date 2018-12-10
+# @version 1.0
+#
+# 详细描述: 玩家聚魂
+#---------------------------------------------------------------------
+#"""Version = 2018-12-10 12:00"""
+#---------------------------------------------------------------------
+
+import GameWorld
+import ShareDefine
+import ChConfig
+import ItemCommon
+import ItemControler
+import PlayerControl
+import ChPyNetSendPack
+import NetPackCommon
+import IpyGameDataPY
+import FormulaControl
+import DataRecordPack
+
+g_GatherSoulLVExpDict = {}  #经验缓存
+g_gatherSoulLVAttrDict = {}  #属性缓存
+
+
+##登录处理
+# @param curPlayer 玩家
+# @return None
+def PlayerLogin(curPlayer):
+    Sync_GatherSoulHoleInfo(curPlayer)
+    return 
+
+
+## 获取聚魂ipy数据
+def GetGatherSoulIpyData(itemID):return IpyGameDataPY.GetIpyGameData("GatherSoul", itemID)
+
+
+## 获取聚魂升级需要经验
+def GetGatherSoulNeedExp(itemID, lv):
+    global g_GatherSoulLVExpDict
+    #((升级经验 * 品质系数)* 神魂系数)*  多属性系数
+
+    itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
+    if not itemData:
+        return 0
+    ipyData = GetGatherSoulIpyData(itemID)
+    if not ipyData:
+        return 0
+    itemColor = itemData.GetItemColor()
+    if lv == 0:  #初始经验
+        expDict = IpyGameDataPY.GetFuncEvalCfg('GatherSoulLevelUp', 4, {})
+        exp = expDict.get(itemColor, 0)
+    else:
+        if lv in g_GatherSoulLVExpDict:
+            exp = g_GatherSoulLVExpDict[lv]
+        else:
+            level = lv + 1  #公式从1开始
+            exp = eval(IpyGameDataPY.GetFuncCompileCfg('GatherSoulLevelUp'))
+            g_GatherSoulLVExpDict[lv] = exp
+            
+        qualityPerDict = IpyGameDataPY.GetFuncEvalCfg('GatherSoulLevelUp', 2, {})
+        if itemColor in qualityPerDict:
+            exp *= float(qualityPerDict[itemColor])
+
+        soulGrade = ipyData.GetSoulGrade()
+        exp *= float(IpyGameDataPY.GetFuncEvalCfg('GatherSoulLevelUp', 4, {}).get(soulGrade, 1))
+            
+        attrTypeCnt = len(ipyData.GetAttrType())
+        specialPer = IpyGameDataPY.GetFuncEvalCfg('GatherSoulLevelUp', 3, {}).get(attrTypeCnt, 1)
+        exp *= float(specialPer)
+    return exp
+
+
+## 获取聚魂属性数值
+def GetGatherSoulAttrValue(itemID, lv):
+    global g_gatherSoulLVAttrDict
+    #((初始属性 + 升级属性 * 品质系数)* 神魂系数 ) * 多属性系数
+
+    itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
+    if not itemData:
+        return {}
+    ipyData = GetGatherSoulIpyData(itemID)
+    if not ipyData:
+        return {}
+    level = lv + 1  #公式从1开始
+    
+    attrTypeList = ipyData.GetAttrType()
+    attrTypeCnt = len(attrTypeList)  #属性条数
+    soulGrade = ipyData.GetSoulGrade()
+    itemColor = itemData.GetItemColor()
+    attrDict = {}
+    for attrType in attrTypeList:
+        attrIpyData = IpyGameDataPY.GetIpyGameData('GatherSoulAttr', attrType)
+        if not attrIpyData:
+            GameWorld.ErrLog('    聚魂属性表未配置该属性 attrType=%s' % attrType)
+            continue
+        key = '%s_%s' % (attrType, level)
+        if key in g_gatherSoulLVAttrDict:
+            value = g_gatherSoulLVAttrDict[key]
+        else:
+            attrFormula = FormulaControl.GetCompileFormula('GatherSoulAttr%s' % attrType, attrIpyData.GetAttrInfo1())
+            if not attrFormula:
+                continue
+            value = eval(attrFormula)
+            g_gatherSoulLVAttrDict[key] = value
+        qualityPerDict = attrIpyData.GetAttrInfo2()
+        if itemColor in qualityPerDict:
+            value *= float(qualityPerDict[itemColor])
+        extraValueDict = attrIpyData.GetAttrInfo4()
+        value += extraValueDict.get(itemColor, 0)
+        #阶段系数
+        value *= float(attrIpyData.GetAttrInfo5().get(soulGrade, 1))
+        #属性条目系数
+        specialPer = attrIpyData.GetAttrInfo3().get(attrTypeCnt, 1)
+        value *= float(specialPer)
+            
+        attrDict[int(attrType)] = int(value)
+    return attrDict
+
+
+def GetGatherSoulMaxLV(itemID):
+    # 获取聚魂最大等级
+    itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
+    if not itemData:
+        return 0
+    GatherSoulMaxLVDict = IpyGameDataPY.GetFuncEvalCfg('GatherSoulMaxLV', 1, {})
+    itemColor = itemData.GetItemColor()
+    GatherSoulMaxLV = GatherSoulMaxLVDict.get(itemColor, 0)
+    return GatherSoulMaxLV
+
+
+def SwitchGatherSoul(curPlayer, srcBackpack, desBackPack, srcIndex, destIndex):
+    # 镶嵌/摘下聚魂
+    if not ((desBackPack == ShareDefine.rptGatherSoul and srcBackpack == ShareDefine.rptTempSwap) \
+            or (srcBackpack == ShareDefine.rptGatherSoul and desBackPack == ShareDefine.rptTempSwap)):
+        return False
+    playerID = curPlayer.GetPlayerID()
+    GatherSoulUnlockDict = IpyGameDataPY.GetFuncEvalCfg("GatherSoulHole", 1, {})
+    maxGatherSoulHole = len(GatherSoulUnlockDict)
+    # 穿
+    if desBackPack == ShareDefine.rptTempSwap:
+        desGatherSoulNum = destIndex
+        if desGatherSoulNum < 0 or desGatherSoulNum >= maxGatherSoulHole:
+            GameWorld.DebugLog("不存在该聚魂孔! desGatherSoulNum=%s" % desGatherSoulNum, playerID)
+            return True
+        
+        if curPlayer.GetLV() < GatherSoulUnlockDict.get(desGatherSoulNum, 0):
+            GameWorld.DebugLog("该聚魂孔未解锁! desGatherSoulNum=%s,needlv=%s" % (desGatherSoulNum, GatherSoulUnlockDict.get(desGatherSoulNum, 0)), playerID)
+            return True
+        
+        srcGatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem 
+                                                     % (ShareDefine.rptGatherSoul, srcIndex))  # 聚魂背包中的值
+        if not srcGatherSoulData:
+            GameWorld.DebugLog("聚魂背包该位置没有聚魂! srcIndex=%s" % srcIndex, playerID)
+            return True
+        srcGatherSoulItemID = ItemControler.GetGatherSoulItemID(srcGatherSoulData)
+        srcItemData = GameWorld.GetGameData().GetItemByTypeID(srcGatherSoulItemID)
+        if not srcItemData:
+            return
+        srcGatherSoulType = srcItemData.GetType()
+        needItemType = IpyGameDataPY.GetFuncEvalCfg("GatherSoulHole", 2, {}).get(desGatherSoulNum, 0)
+        if srcGatherSoulType != needItemType:
+            GameWorld.DebugLog("该聚魂孔不能镶嵌该聚魂类型! desGatherSoulNum=%s,srcGatherSoulType=%s,needItemType=%s" % (desGatherSoulNum, srcGatherSoulType, needItemType), playerID)
+            return
+        
+        srcIpyData = GetGatherSoulIpyData(srcGatherSoulItemID)
+        if not srcIpyData:
+            GameWorld.Log("该聚魂没有配置属性! 无法镶嵌! itemID=%s" % srcGatherSoulItemID, playerID)
+            return True
+        
+        srcGatherSoulAttrTypeList = srcIpyData.GetAttrType()
+        # 判断是否已有镶嵌该属性类型
+        for GatherSoulNum in xrange(maxGatherSoulHole):
+            if GatherSoulNum == desGatherSoulNum:  # 目标孔不判断
+                continue
+            GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % GatherSoulNum, 0)
+            if not GatherSoulData:
+                continue
+            GatherSoulItemID = ItemControler.GetGatherSoulItemID(GatherSoulData)
+            ipyData = GetGatherSoulIpyData(GatherSoulItemID)
+            if not ipyData:
+                continue
+            attrTypeList = ipyData.GetAttrType()
+            if set(srcGatherSoulAttrTypeList) & set(attrTypeList):
+                GameWorld.DebugLog("已有镶嵌该属性类型! 无法镶嵌! GatherSoulHoleNum=%s,attrTypeList=%s,srcGatherSoulAttrTypeList=%s" % (GatherSoulNum, attrTypeList, srcGatherSoulAttrTypeList), playerID)
+                return True
+       
+        desGatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % desGatherSoulNum, 0)  # 孔上的值
+        
+        # 设置聚魂孔数据
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GatherSoulHoleData % desGatherSoulNum, srcGatherSoulData)
+        # 原来的孔数据,则放入聚魂背包中
+        ItemControler.SetVPackItemKeyData(curPlayer, ShareDefine.rptGatherSoul, srcIndex, desGatherSoulData)
+
+    else:  #脱
+        srcGatherSoulNum = srcIndex
+        srcGatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % srcGatherSoulNum, 0)
+        if not srcGatherSoulData:
+            GameWorld.DebugLog("该聚魂孔没有镶嵌聚魂! srcGatherSoulNum=%s, srcGatherSoulData=%s" % (srcGatherSoulNum, srcGatherSoulData), curPlayer.GetPlayerID())
+            return True
+        
+        emptyIndex = ItemCommon.GetEmptyIndexInPack(curPlayer, ShareDefine.rptGatherSoul)
+        if emptyIndex == -1:
+            GameWorld.DebugLog("聚魂背包已满,无法摘下! ", curPlayer.GetPlayerID())
+            return True
+        desGatherSoulData = 0
+        # 摘下设置孔数据为0
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GatherSoulHoleData % srcGatherSoulNum, 0)
+        ItemControler.SetVPackItemKeyData(curPlayer, ShareDefine.rptGatherSoul, emptyIndex, srcGatherSoulData)
+    dataDict = {'desBackPack':desBackPack, 'srcGatherSoulData':srcGatherSoulData, 'desGatherSoulData':desGatherSoulData}
+    DataRecordPack.Cache_FightPowerChangeInfo(curPlayer, ChConfig.PowerDownType_GatherSoul, dataDict)
+    RefreshGatherSoulAttr(curPlayer)
+    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
+    Sync_GatherSoulHoleInfo(curPlayer)
+    return True
+
+
+#// A5 18 聚魂升级 #tagCMGatherSoulUp
+#struct    tagCMGatherSoulUp
+#{
+#    tagHead        Head;
+#    BYTE        PlaceType;    // 位置类型;0-背包,1-孔
+#    WORD        PlaceIndex;    // 位置索引
+#};
+def OnGatherSoulUp(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    placeType = clientData.PlaceType
+    placeIndex = clientData.PlaceIndex
+    if placeType == 0:
+        GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (ShareDefine.rptGatherSoul, placeIndex))
+    elif placeType == 1:
+        GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % (placeIndex), 0)
+    else:
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    if not GatherSoulData:
+        GameWorld.DebugLog("该位置不存在聚魂, 无法升级! placeType=%s,placeIndex=%s" % (placeType, placeIndex), playerID)
+        return
+    
+    GatherSoulItemID = ItemControler.GetGatherSoulItemID(GatherSoulData)
+    GatherSoulItemPlusLV = ItemControler.GetGatherSoulItemPlusLV(GatherSoulData)
+
+    itemData = GameWorld.GetGameData().GetItemByTypeID(GatherSoulItemID)
+    if not itemData:
+        return
+    
+    GatherSoulMaxLV = GetGatherSoulMaxLV(GatherSoulItemID)
+    if GatherSoulItemPlusLV + 1 >= GatherSoulMaxLV:
+        GameWorld.DebugLog('该聚魂已满级,无法升级!GatherSoulMaxLV=%s' % GatherSoulMaxLV)
+        return
+    
+    plusCost = GetGatherSoulNeedExp(GatherSoulItemID, GatherSoulItemPlusLV + 1)
+    plusCost = int(plusCost)
+    if not plusCost:
+        GameWorld.DebugLog("该聚魂无法升级!  placeType=%s,placeIndex=%s,itemID=%s,plusLV=%s" 
+                           % (placeType, placeIndex, GatherSoulItemID, GatherSoulItemPlusLV), playerID)
+        return
+
+    updGatherSoulData = ItemControler.GetGatherSoulItemKeyData(GatherSoulItemID, GatherSoulItemPlusLV + 1)
+    if not PlayerControl.PayMoney(curPlayer, ShareDefine.TYPE_Price_SoulDust, plusCost):
+        curGatherSoulMoney = PlayerControl.GetMoney(curPlayer, ShareDefine.TYPE_Price_SoulDust)
+        GameWorld.DebugLog("聚魂尘点不足,无法升级!placeType=%s,placeIndex=%s,itemID=%s,plusLV=%s,plusCost=%s,curGatherSoulMoney=%s" 
+                           % (placeType, placeIndex, GatherSoulItemID, GatherSoulItemPlusLV, plusCost, curGatherSoulMoney), playerID)
+        return
+    
+    if placeType == 0:
+        ItemControler.SetVPackItemKeyData(curPlayer, ShareDefine.rptGatherSoul, placeIndex, updGatherSoulData)
+    elif placeType == 1:
+        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GatherSoulHoleData % (placeIndex), updGatherSoulData)
+        RefreshGatherSoulAttr(curPlayer)
+        PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
+        Sync_GatherSoulHoleInfo(curPlayer)
+        
+    GameWorld.DebugLog("聚魂升级!placeType=%s,placeIndex=%s,GatherSoulData=%s,updGatherSoulData=%s" 
+                       % (placeType, placeIndex, GatherSoulData, updGatherSoulData), playerID)
+    return
+
+
+#// A5 19 聚魂分解 #tagCMGatherSoulDecompose
+#
+#struct    tagCMGatherSoulDecompose
+#{
+#    tagHead        Head;
+#    BYTE        IsAuto;    // 是否自动分解
+#    BYTE        Count;    // 指定批量分解数,最大不超过50个
+#    WORD        PlaceIndexList[Count];    // 批量分解位置索引列表
+#};
+def OnGatherSoulDecompose(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    isAuto = clientData.IsAuto
+    placeList = clientData.PlaceIndexList
+    
+    delPlaceDict = {}
+    totalSoulDust = 0
+    totalSoulSplinters = 0
+    totalSoulCore = 0
+    giveMaterialDict = {}
+    needPackSpace = 0
+    packIndex = ShareDefine.rptGatherSoul
+    
+    for place in placeList:
+        GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (packIndex, place))
+        if not GatherSoulData:
+            continue
+        
+        GatherSoulItemID = ItemControler.GetGatherSoulItemID(GatherSoulData)
+        GatherSoulItemPlusLV = ItemControler.GetGatherSoulItemPlusLV(GatherSoulData)
+        itemData = GameWorld.GetGameData().GetItemByTypeID(GatherSoulItemID)
+        if not itemData:
+            continue
+        soulidList, soulSplinters, soulCore, soulDust = [], 0, 0, 0
+        if itemData.GetType() == ChConfig.Def_ItemType_GatherSoulExp:  #精华物品读效果值
+            curEff = itemData.GetEffectByIndex(0)
+            soulDust = curEff.GetEffectValue(0)
+        else:
+    
+            soulDust = 0
+            for lv in xrange(GatherSoulItemPlusLV + 1):
+                soulDust += GetGatherSoulNeedExp(GatherSoulItemID, lv)
+                    
+            #多属性的先拆解成单属性的聚魂
+            soulidList, soulSplinters, soulCore = __GetGatherSoulSplitMaterial(GatherSoulItemID)
+            for itemID in soulidList:
+                giveMaterialDict[itemID] = giveMaterialDict.get(itemID, 0) + 1
+                needPackSpace += 1
+            
+        totalSoulSplinters += soulSplinters
+        totalSoulCore += soulCore
+        totalSoulDust += soulDust
+        delPlaceDict[place] = [GatherSoulData, soulidList, int(soulDust), soulSplinters, soulCore]
+        
+    if delPlaceDict:
+        ItemCommon.DelVPackItem(curPlayer, packIndex, delPlaceDict.keys(), ChConfig.ItemDel_GatherSoul)
+    addDataDict = {"delPlaceDict":delPlaceDict, "isAuto":isAuto}
+    if totalSoulDust:
+        totalSoulDust = int(totalSoulDust)
+        PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_SoulDust, totalSoulDust,
+                                ChConfig.Def_GiveMoney_GatherSoulDecompose, addDataDict, False)
+        PlayerControl.NotifyCode(curPlayer, 'hwj_20170807_1', [totalSoulDust, ShareDefine.TYPE_Price_SoulDust])
+    if totalSoulSplinters:
+        PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_SoulSplinters, totalSoulSplinters,
+                                ChConfig.Def_GiveMoney_GatherSoulDecompose, addDataDict, False)
+        PlayerControl.NotifyCode(curPlayer, 'hwj_20170807_1', [totalSoulSplinters, ShareDefine.TYPE_Price_SoulSplinters])
+    if totalSoulCore:
+        PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_SoulCore, totalSoulCore,
+                                ChConfig.Def_GiveMoney_GatherSoulDecompose, addDataDict, False)
+        PlayerControl.NotifyCode(curPlayer, 'hwj_20170807_1', [totalSoulCore, ShareDefine.TYPE_Price_SoulCore])
+        
+    if giveMaterialDict:
+        emptySpace = ItemCommon.GetItemPackSpace(curPlayer, ShareDefine.rptGatherSoul, 1)
+        if emptySpace < needPackSpace:
+            giveMaterialList = [[itemID, itemCnt, 1] for itemID, itemCnt in giveMaterialDict.items()]
+            PlayerControl.SendMailByKey('JHBagFull1', [curPlayer.GetID()], giveMaterialList)
+        else:
+            for itemID, itemCnt in giveMaterialDict.items:
+                ItemControler.GivePlayerItem(curPlayer, itemID, itemCnt, 1, [ShareDefine.rptGatherSoul])
+    GameWorld.DebugLog("聚魂分解: isAuto=%s,PlaceIndexList=%s, delPlaceDict=%s" % (isAuto, placeList, delPlaceDict))
+    return
+
+
+def __GetGatherSoulSplitMaterial(gathersoulID, soulidList=[], soulSplinters=0, soulCore=0):
+    ##拆解多属性聚魂 返回单属性聚魂ID,材料
+    compoundIpyData = IpyGameDataPY.GetIpyGameDataNotLog('GatherSoulCompound', gathersoulID)
+    if compoundIpyData:
+        materialList = compoundIpyData.GetNeedItem()
+        soulSplinters += compoundIpyData.GetNeedSoulSplinters()
+        soulCore += compoundIpyData.GetNeedSoulCore()
+        for itemID in materialList:
+            soulIpyData = GetGatherSoulIpyData(itemID)
+            if soulIpyData and len(soulIpyData.GetAttrType()) > 1:
+                __GetGatherSoulSplitMaterial(itemID, soulidList, soulSplinters, soulCore)
+            else:
+                soulidList.append(itemID)
+    return soulidList, soulSplinters, soulCore
+
+
+#// A5 1C 聚魂合成 #tagCMGatherSoulCompound
+#
+#struct    tagCMGatherSoulCompound
+#{
+#    tagHead        Head;
+#    BYTE        Cnt;
+#    BYTE        PackList[Cnt];    //所在位置 0-背包 1-孔
+#    WORD        IndexList[Cnt];    //物品索引
+#    DWORD        TagItemID;    //合成目标物品ID
+#};
+def OnGatherSoulCompound(index, clientData, tick):
+    ##聚魂合成
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    tagItemID = clientData.TagItemID
+    packList = clientData.PackList
+    indexList = clientData.IndexList
+    GameWorld.DebugLog('    聚魂合成 tagItemID=%s' % tagItemID)
+    ipyData = IpyGameDataPY.GetIpyGameData('GatherSoulCompound', tagItemID)
+    if not ipyData:
+        return
+    if curPlayer.GetLV() < ipyData.GetNeedLV():
+        return
+    
+    materialsIDList = []
+    materialsLVDict = {}
+    indexList1 = []  #背包的聚魂索引
+    indexList2 = []  #孔索引
+    for i, placeType in enumerate(packList):
+        index = indexList[i]
+        if placeType == 0:
+            GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (ShareDefine.rptGatherSoul, index))  # 聚魂背包中的值
+            indexList1.append(index)
+        else:
+            GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % (index), 0)
+            indexList2.append(index)
+        if not GatherSoulData:
+            continue
+        GatherSoulItemID = ItemControler.GetGatherSoulItemID(GatherSoulData)
+        GatherSoulItemPlusLV = ItemControler.GetGatherSoulItemPlusLV(GatherSoulData)
+        materialsIDList.append(GatherSoulItemID) 
+        materialsLVDict[GatherSoulItemID] = GatherSoulItemPlusLV
+    
+    needItemIDList = ipyData.GetNeedItem()
+    if sorted(materialsIDList) != sorted(needItemIDList):
+        GameWorld.DebugLog('    聚魂合成 材料不对 tagItemID=%s, materialsIDList=%s, needItemIDList=%s' % (tagItemID, materialsIDList, needItemIDList))
+        return
+    
+    if 0 not in packList:
+        #如果没有背包的材料要判断格子数
+        emptySpace = ItemCommon.GetItemPackSpace(curPlayer, ShareDefine.rptGatherSoul, 1)
+        if emptySpace < 1:
+            PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_676165", [ShareDefine.rptGatherSoul])
+            GameWorld.DebugLog('    聚魂合成 背包格子数量不足1个')
+            return 
+        
+    costMoneyDict = {ShareDefine.TYPE_Price_SoulSplinters:ipyData.GeNeedSoulSplinters(),
+                     ShareDefine.TYPE_Price_SoulCore:ipyData.GeNeedSoulSplinters(), }
+    for moneyType, costMoney in costMoneyDict:
+        if not PlayerControl.HaveMoney(curPlayer, moneyType, costMoney):
+            return
+    
+    infoDict = {"TagItemID":tagItemID}
+    for moneyType, costMoney in costMoneyDict:
+        PlayerControl.PayMoney(curPlayer, moneyType, costMoney, ChConfig.Def_Cost_ItemProduce, infoDict)
+     
+    totalPoint = 0
+    for itemID in materialsIDList:
+        decompose = 0
+        GatherSoulItemPlusLV = materialsLVDict.get(itemID, 0)
+        for lv in range(1, GatherSoulItemPlusLV + 1):
+            decompose += GetGatherSoulNeedExp(itemID, lv)
+        totalPoint += decompose
+    totalPoint = int(totalPoint)
+    tagItemLV = 0
+
+    GatherSoulMaxLV = GetGatherSoulMaxLV(tagItemID)
+    for lv in xrange(1, GatherSoulMaxLV):
+        needExp = GetGatherSoulNeedExp(tagItemID, lv)
+        if totalPoint < needExp:
+            break
+        tagItemLV = lv
+        totalPoint -= needExp
+    
+    #删除材料物品
+    if indexList1:
+        ItemCommon.DelVPackItem(curPlayer, ShareDefine.rptGatherSoul, indexList1, ChConfig.ItemDel_GatherSoul)
+    if indexList2:
+        for index in indexList2:
+            srcGatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % index, 0)
+            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GatherSoulHoleData % index, 0)
+            dataDict = {'doType':'GatherSoulCompound', 'srcGatherSoulData':srcGatherSoulData, 'desGatherSoulData':0}
+            DataRecordPack.Cache_FightPowerChangeInfo(curPlayer, ChConfig.PowerDownType_GatherSoul, dataDict)
+            
+        Sync_GatherSoulHoleInfo(curPlayer)
+        RefreshGatherSoulAttr(curPlayer)
+        PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
+    #返还多余魂尘
+    if totalPoint > 0:
+        PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_SoulDust, totalPoint)
+    #给新物品
+    curItem = ItemControler.GetOutPutItemObj(tagItemID)
+    curItem.SetUserAttr(ShareDefine.Def_IudetGatherSoulLV, tagItemLV)
+    PlayerItemControler = ItemControler.PlayerItemControler(curPlayer)
+    PlayerItemControler.PutInItem(ShareDefine.rptGatherSoul, curItem, event=[ChConfig.ItemGive_ItemCompound, False, {'indexList1':indexList1, 'indexList2':indexList2, 'soulDust':totalPoint}])
+    
+    curPlayer.Sync_MakeItemAnswer(ShareDefine.Def_mitGatherSoulCompound, 1)
+    return
+
+
+def RefreshGatherSoulAttr(curPlayer):
+    allAttrList = [{} for _ in range(4)]
+    GatherSoulUnlockDict = IpyGameDataPY.GetFuncEvalCfg("GatherSoulHole", 1, {})
+    maxGatherSoulHole = len(GatherSoulUnlockDict)
+    for holeNum in xrange(maxGatherSoulHole):
+        GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % holeNum, 0)
+        if not GatherSoulData:
+            continue
+        GatherSoulItemID = ItemControler.GetGatherSoulItemID(GatherSoulData)
+        GatherSoulItemPlusLV = ItemControler.GetGatherSoulItemPlusLV(GatherSoulData)
+        
+        attrDict = GetGatherSoulAttrValue(GatherSoulItemID, GatherSoulItemPlusLV)
+        
+        if not attrDict:
+            continue
+        GameWorld.DebugLog('    刷聚魂属性 holeNum=%s, attrDict=%s' % (holeNum, attrDict))
+        for attrID, attrValue in attrDict.items():
+            PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrList)
+        
+    # 保存计算值
+    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_GatherSoul, allAttrList)
+    
+    return
+
+
+def Sync_GatherSoulHoleInfo(curPlayer):
+    ##通知聚魂孔信息
+    GatherSoulUnlockDict = IpyGameDataPY.GetFuncEvalCfg("GatherSoulHole", 1, {})
+    maxGatherSoulHole = len(GatherSoulUnlockDict)
+    GatherSoulInfoPack = ChPyNetSendPack.tagMCGatherSoulHoleInfo()
+    GatherSoulInfoPack.Clear()
+    GatherSoulInfoPack.GatherSoulDataList = []
+    for GatherSoulNum in xrange(maxGatherSoulHole):
+        GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % GatherSoulNum, 0)
+        GatherSoulInfoPack.GatherSoulDataList.append(GatherSoulData)
+    GatherSoulInfoPack.Count = len(GatherSoulInfoPack.GatherSoulDataList)
+    NetPackCommon.SendFakePack(curPlayer, GatherSoulInfoPack)
+    return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
index 557d94c..0c0ee25 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -78,3 +78,5 @@
 g_fightpowerChangeDataRecordDict = {} #导致战力降低的各种行为记录
 
 g_fbRobotJobDict = {} #副本机器人职业  {lineID:{objID:job, ...}, ...}
+
+g_gathersoulfbAwardDict = {} #聚魂副本奖励记录{playerID:[[itemID,itemCnt]]}
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
index 62a3bc0..79f1202 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -312,7 +312,8 @@
     Def_mitRecycleAttrFruit,  # 回收魂石
     Def_mitDogzEquipPlus,     # 神兽装备强化
     Def_mitRuneCompound,      # 符印合成
-) = range(1, 23)
+    Def_mitGatherSoulCompound,# 聚魂合成
+) = range(1, 24)
 
 #---写死的技能ID---
 Def_SkillID_AutoTruck = 62220   # 自动运镖buff
@@ -786,7 +787,10 @@
 CDBPlayerRefresh_GodWeaponLV_2,         # 神兵等级 - 类型2 193
 CDBPlayerRefresh_GodWeaponLV_3,         # 神兵等级 - 类型3 194
 CDBPlayerRefresh_GodWeaponLV_4,         # 神兵等级 - 类型4 195
-) = range(146, 196)
+CDBPlayerRefresh_SoulDust,              # 魂尘 196
+CDBPlayerRefresh_SoulSplinters,         # 聚魂碎片 197
+CDBPlayerRefresh_SoulCore,              # 核心环 198
+) = range(146, 199)
 
 TYPE_Price_Gold_Paper_Money = 5    # 金钱类型,(先用礼券,再用金子)
 TYPE_Price_Family_Contribution = 6 # 战盟贡献度(活跃度转换得来)
@@ -801,6 +805,9 @@
 TYPE_Price_TreasureScore = 25    # 寻宝积分
 TYPE_Price_BourseMoney = 26    # 交易所可购买额度
 TYPE_Price_Danjing = 27    # 丹精(丹药回收)
+TYPE_Price_SoulDust = 28    # 魂尘
+TYPE_Price_SoulSplinters = 29    # 聚魂碎片
+TYPE_Price_SoulCore = 30    # 核心环
 
 
 #以下是旧的金钱类型
@@ -828,6 +835,9 @@
                            TYPE_Price_FamilyActivity:CDBPlayerRefresh_FamilyActivity,
                            TYPE_Price_XianyuanCoin:CDBPlayerRefresh_Xianyuancoin,
                            TYPE_Price_Danjing:CDBPlayerRefresh_Danjing,
+                           TYPE_Price_SoulDust:CDBPlayerRefresh_SoulDust,
+                           TYPE_Price_SoulSplinters:CDBPlayerRefresh_SoulSplinters,
+                           TYPE_Price_SoulCore:CDBPlayerRefresh_SoulCore,
                            }
 
 # 高效战斗状态
@@ -925,8 +935,9 @@
 
 #虚拟背包类型, 从255递减
 Def_VPack_TypeList = (
+rptGatherSoul,      # 聚魂背包 254
 rptRune,            # 符印背包 255
-) = range(256 - 1, 256)
+) = range(256 - 2, 256)
 
 
 #武器的手持形式
@@ -1266,7 +1277,7 @@
 Def_IudetRuneSource = 40  # 符印来源 老号0,默认1,合成2(主要用来区分是否合成获得)
 Def_IudetWingProgressValue = 42 #羽翼精炼值
 Def_IudetCreateTime = 44 # 时效物品的创建时间
-
+Def_IudetGatherSoulLV = 46  # 聚魂等级
 # 200~300 宠物数据用
 Def_IudetPet_NPCID = 200  # npcID
 Def_IudetPet_ClassLV = 202  # 阶级
@@ -1330,7 +1341,7 @@
 )=range(5)
 
 # 战斗力模块类型
-Def_MFPType_Max = 25
+Def_MFPType_Max = 26
 ModuleFightPowerTypeList = (
 Def_MFPType_Role, # 角色 0
 Def_MFPType_Equip, # 装备(基本装备位) 1
@@ -1354,6 +1365,7 @@
 Def_MFPType_HorseSoul, # 坐骑魂石 19
 Def_MFPType_MagicWeaponSoul, # 法宝之魂 20
 Def_MFPType_Dogz, # 神兽 21
+Def_MFPType_GatherSoul, # 聚魂 22
 Def_MFPType_Other, # 其他
 
 #以下暂时没用到,改时再处理

--
Gitblit v1.8.0